tags:

views:

158

answers:

4

I might be misunderstanding something, and this may even be impossible, but I would like to sort a IEnumerable<string> alphabetically.

How do I go about it?

Edit: I would really love and adore an in-place solution.

+17  A: 

The same way you'd sort any other enumerable:

var result = myEnumerable.OrderBy(s => s);

or

var result = from s in myEnumerable
             orderby s
             select s;

or (ignoring case)

var result = myEnumerable.OrderBy(s => s,
                                  StringComparer.CurrentCultureIgnoreCase);

Note that, as is usual with LINQ, this creates a new IEnumerable<T> which, when enumerated, returns the elements of the original IEnumerable<T> in sorted order. It does not sort the IEnumerable<T> in-place.


An IEnumerable<T> is read-only, that is, you can only retrieve the elements from it, but cannot modify it directly. If you want to sort a collection of strings in-place, you need to sort the original collection which implements IEnumerable<string>, or turn an IEnumerable<string> into a sortable collection first:

List<string> myList = myEnumerable.ToList();
myList.Sort();

Based on your comment:

_components = (from c in xml.Descendants("component")
               let value = (string)c
               orderby value
               select value
              )
              .Distinct()
              .ToList();

or

_components = xml.Descendants("component")
                 .Select(c => (string)c)
                 .Distinct()
                 .OrderBy(v => v)
                 .ToList();

or (if you want to later add more items to the list and keep it sorted)

_components = xml.Descendants("component")
                 .Select(c => (string)c)
                 .Distinct()
                 .ToList();

_components.Add("foo");
_components.Sort();
dtb
or myEnumerable.OrderByDescending(s => s).
Grozz
+1, could include ignoring case.
sixlettervariables
So, _components = _components.OrderBy(s => s); would be fine?
CatZilla
@CatZilla: That should work, but may not be the best way to solve your actual problem. What is _components, where do you get it from, how do you use it?
dtb
@dtb: Oh, _components is populated from an XML file precisely this way:_components = (from c in xml.Descendants("component")select c.Value.ToString()).Distinct().ToList();And I need to sort it.
CatZilla
`OrderBy` returns `IOrderedEnumerable<T>`. `IOrderedEnumerable<T>` derives from `IEnumerable<T>` so it can be used like `IEnumerable<T>`, but it extends the type, allowing for example, for the use of `ThenBy`.
Maciej Hehl
+3  A: 

It is impossible, but it isn't.

Basically, any sort method is going to copy your IEnumerable into a List, sort the List and then return to you the sorted list, which is an IEnumerable as well as an IList

This means you lose the "continue infinitely" property of an IEnumerable, but then you couldn't sort one like that anyway.

James Curran
Right on. IEnumerable's purpose is to present you with a handle to a series that you can iterate, beginning to end, by continuing to ask for the "next" item. This means that an IEnumerable can be partially iterated before all the contents are known; you don't have to know when you have gone through them all until you have. Sorting (like many things Linq lets you do) requires knowledge of the entire series as an ordered list; the item that would appear first in a sorted series may be the last one returned by a series, and you won't know that unless you know what all the items are.
KeithS
+1  A: 
myEnumerable = myEnumerable.OrderBy(s => s);
Larsenal
+1  A: 

We can't always do it in-place, but we detect when it's possible:

IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src, IComparer<T> cmp)
{
  List<T> listToSort = (src is List<T>) ? (List<T>)src : new List<T>(src);
  listToSort.Sort(cmp);
  return listToSort;
}
IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src, Comparison<T> cmp)
{
  return SortInPlaceIfCan(src, new FuncComparer<T>(cmp));
}
IEnumerable<T> SortInPlaceIfCan(IEnumerable<T> src)
{
  return SortInPlaceIfCan(src, Comparer<T>.Default);
}

This uses the following handy struct:

internal struct FuncComparer<T> : IComparer<T>
{
  private readonly Comparison<T> _cmp;
  public FuncComparer(Comparison<T> cmp)
  {
      _cmp = cmp;
  }
  public int Compare(T x, T y)
  {
      return _cmp(x, y);
  }
}
Jon Hanna
I'm not sure if I'd recommend this. If you have an IEnumerable<T> but don't know the actual type that implements, you probably shouldn't be modifying it. Btw, Array.FunctorComparer<T> is internal.
dtb
On modifying what we have, I took that to be implied in the question looking for in-place; that it implies it. It's a reason to have "InPlaceInCan" in the method name; method names can be even more upfront about risks than the best documentation ;)Yeah, Array.FunctorComparer<T> is internal, but it's trivial. I put it in because it's the best way I could think of in an example for "your functor comparer you have in your go-to set of helper classes".
Jon Hanna
@dtb on second thoughts, changed to use my own (took a look at Array.FunctorComparer again and I prefer mine anyway!)
Jon Hanna