IEnumerable <string>をソートする方法


98

IEnumerable<string>アルファベット順に並べ替える方法を教えてください。これは可能ですか?

編集:インプレースソリューションを作成するにはどうすればよいですか?

回答:


154

他の列挙可能なものを並べ替えるのと同じ方法:

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 <string>を実装する元のコレクションを並べ替えるか、最初にIEnumerable <string>を並べ替え可能なコレクションに変換する必要があります。

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

またはmyEnumerable.OrderByDescending(s => s)。
Grozz

したがって、_components = _components.OrderBy(s => s); 大丈夫でしょうか?
CatZilla

@CatZilla:それはうまくいくはずですが、実際の問題を解決する最良の方法ではないかもしれません。_componentsとは何ですか?どこから入手しますか?どのように使用しますか?
dtb

1
@dtb:ああ、_componentsはXMLファイルから次のように正確に入力されます。そして、私はそれを分類する必要があります。
CatZilla

2
OrderByを返しますIOrderedEnumerable<T>IOrderedEnumerable<T>から派生するIEnumerable<T>ため、のように使用できますIEnumerable<T>が、タイプを拡張して、たとえばの使用を可能にしThenByます。
Maciej Hehl

12

それは不可能ですが、不可能ではありません。

基本的には、任意の並べ替えの方法は、あなたをコピーしようとしているIEnumerableList並べ替え、Listその後、あなたにあるソートされたリスト、返すIEnumerableなどIList

これは、の「無限に継続する」プロパティを失うことを意味しますが、IEnumerableそのようなものをソートすることはできません。


7
右に。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);
  }
}

これをお勧めするかどうかわかりません。IEnumerable <T>はあるが実装する実際の型がわからない場合は、おそらくそれを変更するべきではありません。ところで、Array.FunctorComparer <T>は内部です。
dtb

私たちが持っているものを変更することについて、私はそれをインプレース検索の質問に暗示するようにしました。それが意味すること。メソッド名に「InPlaceInCan」があるのはそのためです。メソッド名は、最良のドキュメントよりもリスクについて前向きである可能性があります;)ええ、Array.FunctorComparer <T>は内部的なものですが、それは簡単です。これは、「ヘルパークラスの主要セットにあるファンクターコンパレータ」の例で考えることができる最良の方法だからです。
Jon Hanna

@dtbについて考え直し、自分のものを使用するように変更(Array.FunctorComparerをもう一度見て、とにかく私のものを好む!)
Jon Hanna

賢いアイデアとネーミング!しかし、なぜダブルキャストアンチパターンではlistToSort = (src is List<T>) ? (List<T>)src : new List<T>(src);?それはどのようにlistToSort = (src as List<T>); if (null == listToSort) listToSort = new List<T>(src);
Jeroen Wiert Pluimers、2013年

1
@JeroenWiertPluimersサンプルコードにも常に問題があります。上記が少し短くて手元の問題に集中したかったので、気にならなかっただけかもしれませんが、例でさえ悪い習慣をやめさせるのは良いことです。
Jon Hanna
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.