2013-01-02 3 views
6

を使用しない方法、私は正常に数字の集合を生成し、配列内の要素の位置をシャッフルするために管理:はEnumerable.OrderByが進行コードを使用してkeySelector

var randomNumbers = Enumerable.Range(0, 100) 
        .OrderBy(x => Guid.NewGuid()); 

すべての機能罰金が、それは一種の投げていますEnumerable.OrderByを理解しようとすると、私の作品の中で馬鹿になる。

var pupils = new[] 
{ 
    new Person() { Name = "Alex", Age = 17 }, 
    new Person() { Name = "Jack", Age = 21 } 
}; 

var query = pupils.OrderBy(x => x.Age); 

それは私が私がソートしたいプロパティを渡しています私の理解だと私はLINQは、明示的なIComparerが指定されていない場合は、コレクションを注文する方法を決定するためにComparer<T>.Defaultを使用することを想定します。たとえば、次のコードを取ります2番目の過負荷このような方法でアレイをシャッフルするために、この合理的なロジックがどのように適用されるのか、私は本当に分かりません。では、LINQを使ってこのような配列をシャッフルできますか?

+0

私はここであなたの質問を理解しません。上記の例では、ageがintであると仮定すると、 'query'は順序付きリストを含みます。そのため、最初の配列はソートされず、シャッフルされません。 – ryadavilli

+0

投稿を更新しました。私は最初のコードサンプルについて話しています。 –

+0

実際のコードでFisher-Yatesをシャッフルしよう。もっと速い。 – nawfal

答えて

5

どうEnumerable.OrderByがkeySelectorを使用しないことがありますか?

Enumerable.OrderBy<T> lazily returns - keySelectorは直接呼び出されません。結果は列挙されると順序を実行するIOrderedEnumerable<T>です。

列挙すると、各要素に対してkeySelectorが1回呼び出されます。キーの順序は要素の新しい順序を定義します。

ここでは、ニフティsample implementationです。


それでは、どのようにLINQは私がこのような配列をシャッフルさせていますか?

var randomNumbers = Enumerable 
    .Range(0, 100) 
    .OrderBy(x => Guid.NewGuid()); 

Guid.NewGuidは、各要素のために呼び出されます。 2番目の要素の呼び出しは、最初の要素の呼び出しよりも高い値または低い値を生成する可能性があります。

randomNumbersは、列挙されるたびに異なる順序を生成するIOrderedEnumerable<int>です。 KeySelectorは、randomNumbersが列挙される度に要素ごとに1回呼び出されます。

2

これはどのように機能しますか?

以下のクエリでは、比較のためにComparer<Guid>.Defaultが使用されています。

.OrderBy(x => Guid.NewGuid()) 

(あなたがOrderBy句自体に生成される)、すべての生成されたGUIDは、実質的に一意であるので、あなたがランダムな順序(間違って理解している)になっていると信じています。
再度クエリを実行すると、GUIDの新しいセットが生成されるたびにシャッフルされた結果が再び表示されます(おそらく)。

定義済みのGUIDを使用する場合は、注文が表示されます。

randomNumbers1randomNumbers2の値は以下の通りです。

var randomGuids = Enumerable.Range(0,10).Select (x => Guid.NewGuid()).ToArray(); 

var randomNumbers1 = Enumerable.Range(0, 10).OrderBy(x => randomGuids[x]); 

var randomNumbers2 = Enumerable.Range(0, 10).OrderBy(x => randomGuids[x]); 

私は本当にこの合理的なロジックのいずれかが、このような方法で配列をシャッフルするために適用できる方法を確認することはできません。

要素の間に順序がないためシャッフルすることができます(例ではGUID)。注文した要素を使用すると、シャッフルされた要素の代わりに順序付けられた出力が得られます。あなたの第2のケースで

+0

これで私にこれを与えてくれました>もっと深い情報が必要です>: –

+0

@Alex、質問を更新 – Tilak

3

あなたは、このようなシャッフルがどのように機能するかを理解するのに非常に近いです。..

pupils.OrderBy(x => x.Age); 

Comparer<int>.Defaultは(人はそのAge、シンプルでソートされている)が使用されています。

最初のケースでは、Comparer<Guid>.Defaultが使用されます。

これはどのように機能しますか?

いつもGuid.NewGuid()(おそらく)異なる/元の/複製されていないGuidが生成されます。今すぐあなたが行うとき

var randomNumbers = Enumerable.Range(0, 100).OrderBy(x => Guid.NewGuid()); 

数字は、生成されたGuidに基づいてソートされます。

ガイドとは何ですか

これらは、16進形式で表された128ビットの整数です。 2^128は非常に大きいので、2つのGuidを生成する可能性は非常にまれです/ほぼ不可能です。 Guidsは何らかのランダム性を示すので、順序もランダムになります。

どのように2つのGuidを比較して注文を実施しますか?

これは簡単な実験に基づいて確認できます。 Do:

したがってComparer<Guid>.Defaultは、guidの文字列表現に基づいています。

別に

あなたはスピードのためにFisher-Yatesシャッフルを使用する必要があります。

public static IEnumerable<T> Shuffle<T>(this IList<T> lst) 
{ 
    Random rnd = new Random(); 
    for (int i = lst.Count - 1; i >= 0; i--) 
    { 
     int j = rnd.Next(i + 1); 
     yield return lst[j]; 
     lst[j] = lst[i]; 
    } 
} 

または、簡潔にするためであってもよいし、ちょうど(高速化のGuidのアプローチよりも、まだすることができる)

public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> lst) 
{ 
    Random rnd = new Random(); 
    return lst.OrderBy(x => rnd.Next()); 
} 
関連する問題