0

IEnumerableリストの要素のランクを計算し、それをメンバーに割り当てたいと思います。ただし、以下のコードは、最初に呼び出された場合にのみ機能します。2回目の呼び出しは、最後のランク値から始まります。したがって、出力012と012の代わりに、012と345を取得しています。

    class MyClass
    {
        public string Name { get; set; }
        public int Rank { get; set; }
    }

    public void SecondTimeRankEvaluvate()
    {
        MyClass[] myArray = new MyClass[] 
        {
            new MyClass() { Name = "Foo" },
            new MyClass() { Name = "Bar" },
            new MyClass() { Name = "Baz" }
        };

        int r = 0;
        var first = myArray.Select(s => { s.Rank = r++; return s; });

        foreach (var item in first)
        {
            Console.Write(item.Rank);
        }
        // Prints 012
        Console.WriteLine("");
        foreach (var item in first)
        {
            Console.Write(item.Rank);
        }
        // Prints 345
    }

r2回目に呼び出されたときに、変数がキャプチャ(クロージャ)されて再利用されていることを理解しています。私はその振る舞いを望まない。ランクを計算して割り当てるためのクリーンな方法はありますか?またr、変数(実際のコード内)は、foreachループが存在するのと同じスコープにありません。それは戻る関数にありますvar first

4

3 に答える 3

6
var first = myArray.Select((s, i) => { s.Rank = i; return s; });
于 2012-04-28T13:50:51.170 に答える
3

LINQは遅延評価を使用し、Select使用するたびにパーツを実行しますmyArray

結果をに保存することで、評価を1回だけ強制的に実行できますList

変化する

var first = myArray.Select(s => { s.Rank = r++; return s; });

var first = myArray.Select(s => { s.Rank = r++; return s; }).ToList();

別の方法は、このように毎回myArray使用して新しいシーケンスに参加することですZip

var first = myArray.Zip(Enumerable.Range(0, int.MaxValue), (s, r) =>
{
    s.Rank = r;
    return s;
});
于 2012-04-28T13:46:12.830 に答える
1

コレクションをクエリしない場合は、LINQを使用しないでください。

配列内の各アイテムを更新するには、forループを使用します。

for (int i = 0; i < myArray.Length; i++)
{
    myArray[i].Rank = i;
}

列挙可能な各アイテムを更新するには、foreachループを使用します。

int r = 0;
foreach (var item in myArray)
{
    item.Rank = r++;
}
于 2012-04-28T13:47:38.670 に答える