1

シーケンスを繰り返すこの機能があります:

public static List<T> Repeat<T>(this IEnumerable<T> lst, int count)
{
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}

今私がする場合:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person()).Repeat(10); 
int i = f.Distinct().Count();

私は100になると思っiていますが、1000になっています!私の質問は厳密には、なぜこれが起こっているのですか? Linq は、 variable と連結する必要がある最初に選択された 100 人であることを理解するのに十分なほど賢くあるべきではありませんretか? ここで..で実行されConcatたときに で使用されると、Selectret.ToList()

編集:

これを行うと、期待どおりに正しい結果が得られます。

var f = d.Select(t => new Person()).ToList().Repeat(10); 
int i = f.Distinct().Count(); //prints 100

もう一度編集します。

オーバーライドしていませんEquals。私は100人のユニークな人物を取得しようとしています(もちろん参照による)。私の質問は、なぜLinqが最初に選択操作を実行してから連結を実行しないのか(もちろん実行時に)、誰かが私に説明できるでしょうか?

4

3 に答える 3

4

問題は、を呼び出さない限り、リストを通過するたびToListにが再列挙され、重複するが作成されることです。この手法は、遅延実行として知られています。d.Select(t => new Person())RepeatPerson

一般にLINQ、シーケンスを列挙するたびに同じシーケンス、または同じ長さのシーケンスを取得するとは想定していません。この効果が望ましくない場合は、次のようにすぐにRepeat呼び出すことで、メソッド内のシーケンスをいつでも「具体化」できます。ToList

public static List<T> Repeat<T>(this IEnumerable<T> lstEnum, int count) {
    if (count < 0)
        throw new ArgumentOutOfRangeException("count");

    var lst = lstEnum.ToList(); // Enumerate only once
    var ret = Enumerable.Empty<T>();

    for (var i = 0; i < count; i++)
        ret = ret.Concat(lst);

    return ret.ToList();
}
于 2012-11-21T19:33:44.723 に答える
1

私の問題をもっと些細なことに分解することができます:

var d = Enumerable.Range(1, 100);
var f = d.Select(t => new Person());

今、本質的に私はこれをやっています:

f = f.Concat(f);

クエリは今まで実行されていないことに注意してください。実行時はf実行のままです。したがって、実行時の最後のステートメントは次のように分類できます。d.Select(t => new Person())

f = f.Concat(f); 
//which is 
f = d.Select(t => new Person()).Concat(d.Select(t => new Person()));

これは、100 + 100 = 200 人の新しいインスタンスを作成することは明らかです。そう

f.Distinct().ToList(); //yields 200, not 100

これは正しい動作です。

編集:拡張メソッドを次のように簡単に書き直すことができます。

public static IEnumerable<T> Repeat<T>(this IEnumerable<T> source, int times)
{
    source = source.ToArray();
    return Enumerable.Range(0, times).SelectMany(_ => source);
}

問題を解決するためにdasblinkenlightの提案を使用しました。

于 2012-11-21T21:32:06.130 に答える
0

Personオブジェクトは個別のオブジェクトです。1000個すべてが異なります。

Personタイプの同等性の定義は何ですか?これをオーバーライドしない場合、その定義は参照の同等性になります。つまり、1000個のオブジェクトすべてが別個のものになります。

于 2012-11-21T19:32:16.477 に答える