Related
I'm trying to using a fluent interface to build a collection, similar to this (simplified) example:
var a = StartWith(1).Add(2).Add(3).Add(4).ToArray();
/* a = int[] {1,2,3,4}; */
The best solution I can come up with add Add() as:
IEnumerable<T> Add<T>(this IEnumerable<T> coll, T item)
{
foreach(var t in coll) yield return t;
yield return item;
}
Which seems to add a lot of overhead that going to be repeated in each call.
IS there a better way?
UPDATE:
in my rush, I over-simplified the example, and left out an important requirement. The last item in the existing coll influences the next item. So, a slightly less simplified example:
var a = StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
/* a = int[] {1,12,123,1234}; */
public static IEnumerable<T> StartWith<T>(T x)
{
yield return x;
}
static public IEnumerable<int> Times10Plus(this IEnumerable<int> coll, int item)
{
int last = 0;
foreach (var t in coll)
{
last = t;
yield return t;
}
yield return last * 10 + item;
}
A bit late to this party, but here are a couple ideas.
First, consider solving the more general problem:
public static IEnumerable<A> AggregateSequence<S, A>(
this IEnumerable<S> items,
A initial,
Func<A, R, A> f)
{
A accumulator = initial;
yield return accumulator;
foreach(S item in items)
{
accumulator = f(accumulator, item);
yield return accumulator;
}
}
And now your program is just new[]{2, 3, 4}.AggregateSequence(1,
(a, s) => a * 10 + s).ToArray()
However that lacks the "fluency" you want and it assumes that the same operation is applied to every element in the sequence.
You are right to note that deeply nested iterator blocks are problematic; they have quadratic performance in time and linear consumption of stack, both of which are bad.
Here's an entertaining way to implement your solution efficiently.
The problem is that you need both cheap access to the "right" end of the sequence, in order to do an operation on the most recently added element, but you also need cheap access to the left end of the sequence to enumerate it. Normal queues and stacks only have cheap access to one end.
Therefore: start by implementing an efficient immutable double-ended queue. This is a fascinating datatype; I have an implementation here using finger trees:
https://blogs.msdn.microsoft.com/ericlippert/2008/01/22/immutability-in-c-part-10-a-double-ended-queue/
https://blogs.msdn.microsoft.com/ericlippert/2008/02/12/immutability-in-c-part-eleven-a-working-double-ended-queue/
Once you have that, your operations are one-liners:
static IDeque<T> StartWith<T>(T t) => Deque<T>.Empty.EnqueueRight(t);
static IDeque<T> Op<T>(this IDeque<T> d, Func<T, T> f) => d.EnqueueRight(f(d.PeekRight()));
static IDeque<int> Times10Plus(this IDeque<int> d, int j) => d.Op(i => i * 10 + j);
Modify IDeque<T> and Deque<T> to implement IEnumerable<T> in the obvious way and you then get ToArray for free. Or do it as an extension method:
static IEnumerable<T> EnumerateFromLeft(this IDeque<T> d)
{
var c = d;
while (!c.IsEmpty)
{
yield return c.PeekLeft();
c = c.DequeueLeft();
}
}
You could do the following:
public static class MySequenceExtensions
{
public static IReadOnlyList<int> Times10Plus(
this IReadOnlyList<int> sequence,
int value) => Add(sequence,
value,
v => sequence[sequence.Count - 1] * 10 + v);
public static IReadOnlyList<T> Starts<T>(this T first)
=> new MySequence<T>(first);
public static IReadOnlyList<T> Add<T>(
this IReadOnlyList<T> sequence,
T item,
Func<T, T> func)
{
var mySequence = sequence as MySequence<T> ??
new MySequence<T>(sequence);
return mySequence.AddItem(item, func);
}
private class MySequence<T>: IReadOnlyList<T>
{
private readonly List<T> innerList;
public MySequence(T item)
{
innerList = new List<T>();
innerList.Add(item);
}
public MySequence(IEnumerable<T> items)
{
innerList = new List<T>(items);
}
public T this[int index] => innerList[index];
public int Count => innerList.Count;
public MySequence<T> AddItem(T item, Func<T, T> func)
{
Debug.Assert(innerList.Count > 0);
innerList.Add(func(item));
return this;
}
public IEnumerator<T> GetEnumerator() => innerList.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}
Note that I'm using IReadOnlyList to make it possible to index into the list in a performant way and be able to get the last element if needed. If you need a lazy enumeration then I think you are stuck with your original idea.
And sure enough, the following:
var a = 1.Starts().Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
Produces the expected result ({1, 12, 123, 1234}) with, what I think is, reasonable performance.
You can do like this:
public interface ISequence
{
ISequenceOp StartWith(int i);
}
public interface ISequenceOp
{
ISequenceOp Times10Plus(int i);
int[] ToArray();
}
public class Sequence : ISequence
{
public ISequenceOp StartWith(int i)
{
return new SequenceOp(i);
}
}
public class SequenceOp : ISequenceOp
{
public List<int> Sequence { get; set; }
public SequenceOp(int startValue)
{
Sequence = new List<int> { startValue };
}
public ISequenceOp Times10Plus(int i)
{
Sequence.Add(Sequence.Last() * 10 + i);
return this;
}
public int[] ToArray()
{
return Sequence.ToArray();
}
}
An then just:
var x = new Sequence();
var a = x.StartWith(1).Times10Plus(2).Times10Plus(3).Times10Plus(4).ToArray();
Java has Collections.singletonList(T) which returns a List<T> of exactly one element. Is there something similar in C# that returns an IList?
IEnumerable<T> enumerable = Enumerable.Repeat(t, 1);
Creates an IEnumerable with one element.
Array implements IList; and the length cannot be modified via Add (as ReadOnly is true).
Thus, SingletonList<int> could be implemented as easily as:
var slist = new int[] { 5 };
You may want to wrap it in a System.Collections.ObjectModel.ReadOnlyCollection<T> so that the single value cannot be changed (if the Java Singleton list works like this). E.g.
var slist = new System.Collections.ObjectModel.ReadOnlyCollection<int>(new int[] { 5 });
You can also create an extension method.
public static IList<T> AsSingletonList<T>(this IEnumerable<T> source)
{
foreach (var item in source)
{
return new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { item });
}
return new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { default(T) });
}
Or one that asserts there is exactly one value in the source:
public static IList<T> AsSingletonList<T>(this IEnumerable<T> source)
{
IList<T> result = null;
foreach (var item in source)
{
if (result != null)
throw new ArgumentOutOfRangeException("source", "Source had more than one value.");
result = new System.Collections.ObjectModel.ReadOnlyCollection<T>(new T[] { item });
}
if (result == null)
throw new ArgumentOutOfRangeException("source", "Source had no values.");
return result;
}
Edit: Used ReadOnlyCollection<T> to prevent mutation of the single value.
Note: While I think the other answers are correct, the List<T> by default has a capacity of 10 - which is a tiny bit wasteful.
To answer your question, no. Sadly there is nothing built in, although it would often be useful when working with IEnumerable. You'll have to roll your own.
Update
Instead of using workarounds, here's an example of an efficient and immutable SingletonList that implements IList<T>:
Usage
SingletonList<int> bling = new SingletonList<int>(10);
Code
public class SingletonList<T> : IList<T>
{
private readonly T _item;
public SingletonList(T item)
{
_item = item;
}
public IEnumerator<T> GetEnumerator()
{
yield return _item;
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public void Add(T item)
{
throw new NotSupportedException("Add not supported.");
}
public void Clear()
{
throw new NotSupportedException("Clear not supported.");
}
public bool Contains(T item)
{
if (item == null) return _item == null;
return item.Equals(_item);
}
public void CopyTo(T[] array, int arrayIndex)
{
if (array == null) throw new ArgumentNullException("array");
array[arrayIndex] = _item;
}
public bool Remove(T item)
{
throw new NotSupportedException("Remove not supported.");
}
public int Count
{
get { return 1; }
}
public bool IsReadOnly
{
get { return true; }
}
public int IndexOf(T item)
{
return Contains(item) ? 0 : -1;
}
public void Insert(int index, T item)
{
throw new NotSupportedException("Insert not supported.");
}
public void RemoveAt(int index)
{
throw new NotSupportedException("RemoveAt not supported.");
}
public T this[int index]
{
get
{
if (index == 0) return _item;
throw new IndexOutOfRangeException();
}
set { throw new NotSupportedException("Set not supported."); }
}
}
public static class IListExtensions
{
public static IList<T> SingletonList<T>(this IList<T> iList, T item)
{
return Enumerable.Range(0, 1).Select(i => item).ToList().AsReadOnly();
// or
var Result = new List<T>();
Result.Add(item);
return Result.AsReadOnly();
}
}
In C#, you can use a list initializer with one element:
var x = new List<int> { 3 };
Contrary to singletonList, this list is mutable. If you want something immutable, you can call AsReadOnly() on the resulting object:
// Looks strange, but, yes, this is actually valid C#.
var x = new List<int> { 3 }.AsReadOnly();
This is a first for me: I am submitting an answer ... what I have to say does not lead itself to a comment, imho ... to a question which I think I do not fully understand ... in order to better understand the question. Consider:
public class singletonList<T> : List<T>
{
public singletonList(T theValue) { base.Add(theValue); }
public new void Add(T anotherValue) {}
public new void AddRange(T anotherValue) {}
public new void Clear() {}
public new void Insert(int index, T anotherValue) {}
public new void ToArray() {}
}
This will create a new List of whatever Type which allows only one instance of its value-Type to exist inside the List. Obviously it's not fully 'fleshed-out' since you could still use 'InsertRange' and other List altering commands.
Here's a test verifying its 'immutable' for the internal List operators masked-out by the use of 'new' in their declarations.
var q = new singletonList<int>(99);
q.Add(100);
q.Clear();
q.Insert(0, 788);
I doubt this is what the OP wants, but I am curious if this perhaps does, meet the OP's spec in any way.
In spite of ChibaCity's kind explanations, I am still utterly baffled why one would ever want to use a List that contained only one element.
Thanks in advance for educating me, and if the cost of enlightenment is loss of votes, or face ... no problem; at my age I am not running for anything except staying in place, and face is best forgotten :)
I passed a new[] { alreadyDeclaredVariable } into the function. That's one way to do it, just making an in-place array of 1 element.
I have a class and want to work with it as Lists: e.g. List<int>, List<string>, ... , List<T>
I have a class Randomizor which will take the collection data type that will be shuffled. How can I do so?
class Randomizor<T>
{
public Randomizor()
{
}
public Array Shuffle(Array toShuffle)
{
}
}
Create a generic class like so:
class Randomizer<TList, TType> where TList : IList<TType>
{
public TList Randomize(TList list)
{
// ...
}
}
Or like so:
class Randomizer<T>
{
public IList<T> Randomize(IList<T> list)
{
// ...
}
}
Not very clear question... do you mean something like this?
public static class Randomizer<T>
{
public static T GetRandom(List<T> list)
{
T value = default(T);
// Perform some random logic.
return value;
}
}
EDIT: I found two superior impementations after a little digging so I would suggest those in preference.
An extension method for this purpose and already been suggested previously here
I include the code paraphrased to Shuffle below.
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
T [] copy = source.ToArray ();
for (int i = copy.Length - 1; i >= 0; i--)
{
int index = random.Next (i + 1);
yield return copy [index];
copy [index] = copy [i];
}
}
And an interesting solution adapted from this linq approach
public static IEnumerable<T> Shuffle<T> (this IEnumerable<T> source)
{
Random random = new Random ();
return source.OrderBy(i => Random.Next()).AsEnumerable();
}
The orignal answer but slower than the edits
public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> sequence)
{
Random random = new Random();
List<T> copy = sequence.ToList();
while (copy.Count > 0)
{
int index = random.Next(copy.Count);
yield return copy[index];
copy.RemoveAt(index);
}
}
If you like one of these you should up vote the linked answer.
If you are very concerned about randomness, you could upgrade to one of the RNG algorithms from the Crypto API and seed it with some non deterministic value, like somthing generated from recent mouse activity. I suspect that would be overkill and it would degrade performance.
class Randomizor<T>
{
public Randomizor()
{
}
public List<T> Shuffle(List<T> toShuffle)
{
}
}
class Randomizer<T>
{
public Randomizer(ICollection<T> collection)
{
//Do something with collection using T as the type of the elements
}
}
However you may want to go for a generic extension method
static class Randomizer
{
public static void Randomize<T>(this ICollection<T> collection)
{
//randomize the collection
}
}
and the usage:
List<int> list = new List<int> { 1, 2, 3, 4, 5 };
list.Randomize();
Maybe like this:
public List<T> Shuffle<T>(List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
Or as an extension method
public static class Extensions
{
public static List<T> Shuffle<T>(this List<T> toShuffle)
{
return toShuffle.OrderBy(x => Guid.NewGuid()).ToList();
}
}
When I want to make a value type read-only outside of my class I do this:
public class myClassInt
{
private int m_i;
public int i {
get { return m_i; }
}
public myClassInt(int i)
{
m_i = i;
}
}
What can I do to make a List<T> type readonly (so they can't add/remove elements to/from it) outside of my class? Now I just declare it public:
public class myClassList
{
public List<int> li;
public myClassList()
{
li = new List<int>();
li.Add(1);
li.Add(2);
li.Add(3);
}
}
You can expose it AsReadOnly. That is, return a read-only IList<T> wrapper. For example ...
public ReadOnlyCollection<int> List
{
get { return _lst.AsReadOnly(); }
}
Just returning an IEnumerable<T> is not sufficient. For example ...
void Main()
{
var el = new ExposeList();
var lst = el.ListEnumerator;
var oops = (IList<int>)lst;
oops.Add( 4 ); // mutates list
var rol = el.ReadOnly;
var oops2 = (IList<int>)rol;
oops2.Add( 5 ); // raises exception
}
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst; }
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
Steve's answer also has a clever way to avoid the cast.
There is limited value in attempting to hide information to such an extent. The type of the property should tell users what they're allowed to do with it. If a user decides they want to abuse your API, they will find a way. Blocking them from casting doesn't stop them:
public static class Circumventions
{
public static IList<T> AsWritable<T>(this IEnumerable<T> source)
{
return source.GetType()
.GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance)
.Select(f => f.GetValue(source))
.OfType<IList<T>>()
.First();
}
}
With that one method, we can circumvent the three answers given on this question so far:
List<int> a = new List<int> {1, 2, 3, 4, 5};
IList<int> b = a.AsReadOnly(); // block modification...
IList<int> c = b.AsWritable(); // ... but unblock it again
c.Add(6);
Debug.Assert(a.Count == 6); // we've modified the original
IEnumerable<int> d = a.Select(x => x); // okay, try this...
IList<int> e = d.AsWritable(); // no, can still get round it
e.Add(7);
Debug.Assert(a.Count == 7); // modified original again
Also:
public static class AlexeyR
{
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
}
IEnumerable<int> f = a.AsReallyReadOnly(); // really?
IList<int> g = f.AsWritable(); // apparently not!
g.Add(8);
Debug.Assert(a.Count == 8); // modified original again
To reiterate... this kind of "arms race" can go on for as long as you like!
The only way to stop this is to completely break the link with the source list, which means you have to make a complete copy of the original list. This is what the BCL does when it returns arrays. The downside of this is that you are imposing a potentially large cost on 99.9% of your users every time they want readonly access to some data, because you are worried about the hackery of 00.1% of users.
Or you could just refuse to support uses of your API that circumvent the static type system.
If you want a property to return a read-only list with random access, return something that implements:
public interface IReadOnlyList<T> : IEnumerable<T>
{
int Count { get; }
T this[int index] { get; }
}
If (as is much more common) it only needs to be enumerable sequentially, just return IEnumerable:
public class MyClassList
{
private List<int> li = new List<int> { 1, 2, 3 };
public IEnumerable<int> MyList
{
get { return li; }
}
}
UPDATE Since I wrote this answer, C# 4.0 came out, so the above IReadOnlyList interface can take advantage of covariance:
public interface IReadOnlyList<out T>
And now .NET 4.5 has arrived and it has... guess what...
IReadOnlyList interface
So if you want to create a self-documenting API with a property that holds a read-only list, the answer is in the framework.
JP's answer regarding returning IEnumerable<int> is correct (you can down-cast to a list), but here is a technique that prevents the down-cast.
class ExposeList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.Select(x => x); } // Identity transformation.
}
public ReadOnlyCollection<int> ReadOnly
{
get { return _lst.AsReadOnly(); }
}
}
The identity transformation during enumeration effectively creates a compiler-generated iterator - a new type which is not related to _lst in any way.
Eric Lippert has a series of articles on Immutability In C# on his blog.
The first article in the series can be found here.
You might also find useful Jon Skeet's answer to a similar question.
public List<int> li;
Don't declare public fields, it's generally considered bad practice... wrap it in a property instead.
You can expose your collection as a ReadOnlyCollection :
private List<int> li;
public ReadOnlyCollection<int> List
{
get { return li.AsReadOnly(); }
}
public class MyClassList
{
private List<int> _lst = new List<int>() { 1, 2, 3 };
public IEnumerable<int> ListEnumerator
{
get { return _lst.AsReadOnly(); }
}
}
To check it
MyClassList myClassList = new MyClassList();
var lst= (IList<int>)myClassList.ListEnumerator ;
lst.Add(4); //At this point ypu will get exception Collection is read-only.
public static IEnumerable<T> AsReallyReadOnly<T>(this IEnumerable<T> source)
{
foreach (T t in source) yield return t;
}
if I add to Earwicker's example
...
IEnumerable<int> f = a.AsReallyReadOnly();
IList<int> g = f.AsWritable(); // finally can't get around it
g.Add(8);
Debug.Assert(a.Count == 78);
I get InvalidOperationException: Sequence contains no matching element.
So I came across an interesting problem today. We have a WCF web service that returns an IList. Not really a big deal until I wanted to sort it.
Turns out the IList interface doesn't have a sort method built in.
I ended up using the ArrayList.Adapter(list).Sort(new MyComparer()) method to solve the problem but it just seemed a bit "ghetto" to me.
I toyed with writing an extension method, also with inheriting from IList and implementing my own Sort() method as well as casting to a List but none of these seemed overly elegant.
So my question is, does anyone have an elegant solution to sorting an IList
You can use LINQ:
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
This question inspired me to write a blog post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
I think that, ideally, the .NET Framework would include a static sorting method that accepts an IList<T>, but the next best thing is to create your own extension method. It's not too hard to create a couple of methods that will allow you to sort an IList<T> as you would a List<T>. As a bonus you can overload the LINQ OrderBy extension method using the same technique, so that whether you're using List.Sort, IList.Sort, or IEnumerable.OrderBy, you can use the exact same syntax.
public static class SortExtensions
{
// Sorts an IList<T> in place.
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
}
// Sorts in IList<T> in place, when T is IComparable<T>
public static void Sort<T>(this IList<T> list) where T: IComparable<T>
{
Comparison<T> comparison = (l, r) => l.CompareTo(r);
Sort(list, comparison);
}
// Convenience method on IEnumerable<T> to allow passing of a
// Comparison<T> delegate to the OrderBy method.
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
{
return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
}
}
// Wraps a generic Comparison<T> delegate in an IComparer to make it easy
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
private readonly Comparison<T> _comparison;
public ComparisonComparer(Comparison<T> comparison)
{
_comparison = comparison;
}
public int Compare(T x, T y)
{
return _comparison(x, y);
}
public int Compare(object o1, object o2)
{
return _comparison((T)o1, (T)o2);
}
}
With these extensions, sort your IList just like you would a List:
IList<string> iList = new []
{
"Carlton", "Alison", "Bob", "Eric", "David"
};
// Use the custom extensions:
// Sort in-place, by string length
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));
// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));
There's more info in the post: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
How about using LINQ To Objects to sort for you?
Say you have a IList<Car>, and the car had an Engine property, I believe you could sort as follows:
from c in list
orderby c.Engine
select c;
Edit: You do need to be quick to get answers in here. As I presented a slightly different syntax to the other answers, I will leave my answer - however, the other answers presented are equally valid.
You're going to have to do something like that i think (convert it into a more concrete type).
Maybe take it into a List of T rather than ArrayList, so that you get type safety and more options for how you implement the comparer.
The accepted answer by #DavidMills is quite good, but I think it can be improved upon. For one, there is no need to define the ComparisonComparer<T> class when the framework already includes a static method Comparer<T>.Create(Comparison<T>). This method can be used to create an IComparison on the fly.
Also, it casts IList<T> to IList which has the potential to be dangerous. In most cases that I have seen, List<T> which implements IList is used behind the scenes to implement IList<T>, but this is not guaranteed and can lead to brittle code.
Lastly, the overloaded List<T>.Sort() method has 4 signatures and only 2 of them are implemented.
List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
The below class implements all 4 List<T>.Sort() signatures for the IList<T> interface:
using System;
using System.Collections.Generic;
public static class IListExtensions
{
public static void Sort<T>(this IList<T> list)
{
if (list is List<T> listImpl)
{
listImpl.Sort();
}
else
{
var copy = new List<T>(list);
copy.Sort();
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
{
if (list is List<T> listImpl)
{
listImpl.Sort(comparison);
}
else
{
var copy = new List<T>(list);
copy.Sort(comparison);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
{
if (list is List<T> listImpl)
{
listImpl.Sort(comparer);
}
else
{
var copy = new List<T>(list);
copy.Sort(comparer);
Copy(copy, 0, list, 0, list.Count);
}
}
public static void Sort<T>(this IList<T> list, int index, int count,
IComparer<T> comparer)
{
if (list is List<T> listImpl)
{
listImpl.Sort(index, count, comparer);
}
else
{
var range = new List<T>(count);
for (int i = 0; i < count; i++)
{
range.Add(list[index + i]);
}
range.Sort(comparer);
Copy(range, 0, list, index, count);
}
}
private static void Copy<T>(IList<T> sourceList, int sourceIndex,
IList<T> destinationList, int destinationIndex, int count)
{
for (int i = 0; i < count; i++)
{
destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
}
}
}
Usage:
class Foo
{
public int Bar;
public Foo(int bar) { this.Bar = bar; }
}
void TestSort()
{
IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
IList<Foo> foos = new List<Foo>()
{
new Foo(1),
new Foo(4),
new Foo(5),
new Foo(3),
new Foo(2),
};
ints.Sort();
foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
}
The idea here is to leverage the functionality of the underlying List<T> to handle sorting whenever possible. Again, most IList<T> implementations that I have seen use this. In the case when the underlying collection is a different type, fallback to creating a new instance of List<T> with elements from the input list, use it to do the sorting, then copy the results back to the input list. This will work even if the input list does not implement the IList interface.
try this **USE ORDER BY** :
public class Employee
{
public string Id { get; set; }
public string Name { get; set; }
}
private static IList<Employee> GetItems()
{
List<Employee> lst = new List<Employee>();
lst.Add(new Employee { Id = "1", Name = "Emp1" });
lst.Add(new Employee { Id = "2", Name = "Emp2" });
lst.Add(new Employee { Id = "7", Name = "Emp7" });
lst.Add(new Employee { Id = "4", Name = "Emp4" });
lst.Add(new Employee { Id = "5", Name = "Emp5" });
lst.Add(new Employee { Id = "6", Name = "Emp6" });
lst.Add(new Employee { Id = "3", Name = "Emp3" });
return lst;
}
**var lst = GetItems().AsEnumerable();
var orderedLst = lst.OrderBy(t => t.Id).ToList();
orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**
Found this thread while I was looking for a solution to the exact problem described in the original post. None of the answers met my situation entirely, however. Brody's answer was pretty close. Here is my situation and solution I found to it.
I have two ILists of the same type returned by NHibernate and have emerged the two IList into one, hence the need for sorting.
Like Brody said I implemented an ICompare on the object (ReportFormat) which is the type of my IList:
public class FormatCcdeSorter:IComparer<ReportFormat>
{
public int Compare(ReportFormat x, ReportFormat y)
{
return x.FormatCode.CompareTo(y.FormatCode);
}
}
I then convert the merged IList to an array of the same type:
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
Then sort the array:
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
Since one-dimensional array implements the interface System.Collections.Generic.IList<T>, the array can be used just like the original IList.
Useful for grid sorting this method sorts list based on property names. As follow the example.
List<MeuTeste> temp = new List<MeuTeste>();
temp.Add(new MeuTeste(2, "ramster", DateTime.Now));
temp.Add(new MeuTeste(1, "ball", DateTime.Now));
temp.Add(new MeuTeste(8, "gimm", DateTime.Now));
temp.Add(new MeuTeste(3, "dies", DateTime.Now));
temp.Add(new MeuTeste(9, "random", DateTime.Now));
temp.Add(new MeuTeste(5, "call", DateTime.Now));
temp.Add(new MeuTeste(6, "simple", DateTime.Now));
temp.Add(new MeuTeste(7, "silver", DateTime.Now));
temp.Add(new MeuTeste(4, "inn", DateTime.Now));
SortList(ref temp, SortDirection.Ascending, "MyProperty");
private void SortList<T>(
ref List<T> lista
, SortDirection sort
, string propertyToOrder)
{
if (!string.IsNullOrEmpty(propertyToOrder)
&& lista != null
&& lista.Count > 0)
{
Type t = lista[0].GetType();
if (sort == SortDirection.Ascending)
{
lista = lista.OrderBy(
a => t.InvokeMember(
propertyToOrder
, System.Reflection.BindingFlags.GetProperty
, null
, a
, null
)
).ToList();
}
else
{
lista = lista.OrderByDescending(
a => t.InvokeMember(
propertyToOrder
, System.Reflection.BindingFlags.GetProperty
, null
, a
, null
)
).ToList();
}
}
}
Here's an example using the stronger typing. Not sure if it's necessarily the best way though.
static void Main(string[] args)
{
IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
List<int> stronglyTypedList = new List<int>(Cast<int>(list));
stronglyTypedList.Sort();
}
private static IEnumerable<T> Cast<T>(IEnumerable list)
{
foreach (T item in list)
{
yield return item;
}
}
The Cast function is just a reimplementation of the extension method that comes with 3.5 written as a normal static method. It is quite ugly and verbose unfortunately.
In VS2008, when I click on the service reference and select "Configure Service Reference", there is an option to choose how the client de-serializes lists returned from the service.
Notably, I can choose between System.Array, System.Collections.ArrayList and System.Collections.Generic.List
using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
That's pretty !ghetto.
Found a good post on this and thought I'd share. Check it out HERE
Basically.
You can create the following class and IComparer Classes
public class Widget {
public string Name = string.Empty;
public int Size = 0;
public Widget(string name, int size) {
this.Name = name;
this.Size = size;
}
}
public class WidgetNameSorter : IComparer<Widget> {
public int Compare(Widget x, Widget y) {
return x.Name.CompareTo(y.Name);
}
}
public class WidgetSizeSorter : IComparer<Widget> {
public int Compare(Widget x, Widget y) {
return x.Size.CompareTo(y.Size);
}
}
Then If you have an IList, you can sort it like this.
List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget("Zeta", 6));
widgets.Add(new Widget("Beta", 3));
widgets.Add(new Widget("Alpha", 9));
widgets.Sort(new WidgetNameSorter());
widgets.Sort(new WidgetSizeSorter());
But Checkout this site for more information... Check it out HERE
Is this a valid solution?
IList<string> ilist = new List<string>();
ilist.Add("B");
ilist.Add("A");
ilist.Add("C");
Console.WriteLine("IList");
foreach (string val in ilist)
Console.WriteLine(val);
Console.WriteLine();
List<string> list = (List<string>)ilist;
list.Sort();
Console.WriteLine("List");
foreach (string val in list)
Console.WriteLine(val);
Console.WriteLine();
list = null;
Console.WriteLine("IList again");
foreach (string val in ilist)
Console.WriteLine(val);
Console.WriteLine();
The result was:
IList
B
A
C
List
A
B
C
IList again
A
B
C
This looks MUCH MORE SIMPLE if you ask me. This works PERFECTLY for me.
You could use Cast() to change it to IList then use OrderBy():
var ordered = theIList.Cast<T>().OrderBy(e => e);
WHERE T is the type eg. Model.Employee or Plugin.ContactService.Shared.Contact
Then you can use a for loop and its DONE.
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>();
foreach (var item in ordered)
{
ContactItems.Add(item);
}
Convert your IList into List<T> or some other generic collection and then you can easily query/sort it using System.Linq namespace (it will supply bunch of extension methods)