webdevqa.jp.net

LINQを使用した順序の保持

LINQ to Objects命令を順序付き配列で使用します。配列の順序が変更されていないことを確認するために、どの操作を行うべきではありませんか?

341
Matthieu Durut

System.Linq.Enumerable のメソッドを調べ、IEnumerable以外の結果を返したものはすべて破棄しました。それぞれのコメントを確認して、結果の順序がソースの順序とどのように異なるかを判断しました。

順序を絶対に保持します。インデックスによってソース要素を結果要素にマッピングできます

  • AsEnumerable
  • キャスト
  • 連結
  • 選択する
  • ToArray
  • ToList

順序を保持します。要素はフィルターされますが、並べ替えられません。

  • 明確な
  • を除く
  • 交差する
  • OfType
  • スキップ
  • SkipWhile
  • 取る
  • TakeWhile
  • どこ
  • Zip(.net 4の新機能)

順序を破壊する-どの順序で結果が期待されるかはわかりません。

  • ToDictionary
  • 見上げる

順序を明示的に再定義-これらを使用して結果の順序を変更します

  • OrderBy
  • OrderByDescending
  • ThenBy
  • ThenByDescending

いくつかのルールに従って順序を再定義します。

  • GroupBy-IGroupingオブジェクトは、各IGroupingの最初のキーを生成したソース内の要素の順序に基づいた順序で生成されます。グループ化の要素は、ソースに表示される順序で生成されます。
  • GroupJoin-GroupJoinは、outerの要素の順序を保持し、outerの各要素について、innerからの一致する要素の順序を保持します。
  • 結合-外側の要素の順序を保持し、これらの各要素について、内側の一致する要素の順序を保持します。
  • SelectMany-ソースの各要素に対して、セレクターが呼び出され、値のシーケンスが返されます。
  • Union-このメソッドによって返されるオブジェクトが列挙されると、Unionはその順序で最初と2番目を列挙し、まだ生成されていない各要素を生成します。

編集:私はこれに基づいて保存順序にDistinctを移動しました 実装

    private static IEnumerable<TSource> DistinctIterator<TSource>
      (IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
    {
        Set<TSource> set = new Set<TSource>(comparer);
        foreach (TSource element in source)
            if (set.Add(element)) yield return element;
    }
603
Amy B

あなたは実際にSQLについて話しているのですか、それとも配列についてですか?別の言い方をすれば、LINQ to SQLまたはLINQ to Objectsを使用していますか?

LINQ to Objects演算子は、実際には元のデータソースを変更しません。データソースによって効果的にサポートされるシーケンスを構築します。順序を変更する操作は、OrderBy/OrderByDescending/ThenBy/ThenByDescendingのみです。それでも、それらは均等に順序付けられた要素に対して安定しています。もちろん、多くの操作はいくつかの要素を除外しますが、返される要素は同じ順序になります。

別のデータ構造に変換する場合、例えばToLookupまたはToDictionaryでは、その時点で順序が維持されるとは思いませんが、とにかく多少異なります。 (同じキーにマッピングする値の順序は、ルックアップのために保持されますが、信じています。)

31
Jon Skeet

配列で作業している場合、SQLではなくLINQ-to-Objectsを使用しているように聞こえます。確認できますか?ほとんどのLINQ操作は何も並べ替えません(出力は入力と同じ順序になります)-別の並べ替え(OrderBy [Descending]/ThenBy [Descending])を適用しないでください。

[編集:ジョンがより明確に述べたように。 LINQは通常、newシーケンスを作成し、元のデータはそのままにします]

辞書は特定のソート順を尊重しないため、データをDictionary<,>(ToDictionary)にプッシュするとデータがスクランブルされることに注意してください。

ただし、最も一般的なもの(選択、場所、スキップ、テイク)は問題ありません。

7
Marc Gravell

公式のドキュメントを参照する同様の質問で素晴らしい答えを見つけました。引用するには:

Enumerableメソッド(List<T>に適用されるLINQ to Objects)の場合、SelectWhere、またはGroupByによって返される要素の順序に依存できます。 。これは、ToDictionaryDistinctのような本質的に順序付けられていないものには当てはまりません。

Enumerable.GroupBy ドキュメントから:

IGrouping<TKey, TElement>オブジェクトは、各IGrouping<TKey, TElement>の最初のキーを生成したソース内の要素の順序に基づいた順序で生成されます。グループ化の要素は、sourceに現れる順序で生成されます。

これは、IQueryable拡張メソッド(他のLINQプロバイダー)には必ずしも当てはまりません。

ソース: LINQの列挙可能なメソッドは要素の相対的な順序を維持しますか?

3
Curtis Yallop

「group by」または「order by」は、順序を変更する可能性があります。

2
leppie

ここでの質問は、特にLINQ-to-Objectsについて言及しています。

代わりにLINQ-to-SQLを使用している場合、次のようなものを強制しない限り、そこに順序はありません。

mysqlresult.OrderBy(e=>e.SomeColumn)

LINQ-to-SQLでこれを行わない場合、結果の順序は、同じデータであっても後続のクエリ間で異なり、断続的なバグを引き起こす可能性があります。

0
andrew pate