2010-09-02 2 views

ответ

114

То же, как вы бы сортировать любые другие перечислимы:

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

или

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

или (игнорируя случай)

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

Обратите внимание, что, как обычно, с помощью LINQ , это создает новый IEnumerable <T>, который при перечислении возвращает элементы оригинал IEnumerable <T> в отсортированном виде. Он не сортирует IEnumerable <T> на месте.


IEnumerable <T> только для чтения, то есть, вы можете только извлечь элементы из него, но не может изменить его непосредственно. Если вы хотите, чтобы отсортировать коллекцию строк в месте, вам необходимо отсортировать оригинальную коллекцию, которая реализует IEnumerable < снабжать струну, тетиве и т.п. >, или превратить IEnumerable < строку > в сортируемую коллекцию первым:

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

Основываясь на ваш комментарий:

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

или

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

или (если вы хотите, чтобы позже добавить элементы в список и держать его отсортирован)

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

_components.Add("foo"); 
_components.Sort(); 
+0

или myEnumerable.OrderByDescending (s => s). – Grozz

+0

+1, может включать игнорирование случая. – user7116

+0

Итак, _components = _components.OrderBy (s => s); было бы хорошо? – CatZilla

8

Это невозможно, но это не так.

В принципе, любой метод сортировки собирается скопировать ваш IEnumerable в List, сортировать List, а затем вернуться к вам отсортированный список, который является IEnumerable, а как IList.

Это означает, что вы потеряете свойство «продолжать бесконечно» IEnumerable, но тогда вы все равно не можете сортировать.

+6

Прямо на. Цель IEnumerable состоит в том, чтобы представить вам дескриптор серии, которую вы можете продолжить, начиная с конца, продолжая запрашивать «следующий» элемент. Это означает, что IEnumerable может быть частично повторен до того, как все содержимое будет известно; вам не нужно знать, когда вы прошли через них, пока не получите. Сортировка (как и многие вещи, которые позволяет Linq) требует знания всей серии как упорядоченного списка; элемент, который будет отображаться первым в отсортированной серии, может быть последним, возвращаемым серией, и вы не будете знать этого, если не знаете, что все элементы. – KeithS

2

Мы не всегда можем сделать это на месте, но мы обнаруживаем, когда это возможно:

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); 
} 

При этом используется следующая удобная структура:

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); 
    } 
} 
+0

Я не уверен, рекомендую ли я это. Если у вас есть IEnumerable , но вы не знаете фактического типа, который реализуется, вы, вероятно, не должны его изменять. Btw, Array.FunctorComparer является внутренним. – dtb

+0

При изменении того, что у нас есть, я понял, что подразумевается в вопросе поиска на месте; что это подразумевает. Это причина наличия «InPlaceInCan» в имени метода; имена методов могут быть еще более откровенными относительно рисков, чем лучшая документация;) Да, Array.FunctorComparer является внутренним, но это тривиально. Я вложил его, потому что это лучший способ, о котором я мог думать, в примере для «вашего компаратора-функтора, который у вас есть в вашем наборе вспомогательных классов». –

+0

@dtb на вторых мыслях, изменил, чтобы использовать мои собственные (посмотрел на Array.FunctorComparer снова, и я все равно предпочитаю мой!) –

Смежные вопросы