2012-04-28 11 views
0

IEnumerableリストの要素のランクを計算し、そのメンバーに割り当てる必要があります。しかし、以下のコードは1回目の呼び出し時にのみ機能します。 2回目のコールは、最後のランク値から開始します。だからではなく、出力012と012の、私は、変数rは(閉鎖)を捕獲し、2回目と呼ばれたときに再利用されていることを理解し012と345IEnumerable <T>のランクを計算してタイプTに格納する方法

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 
    } 

を取得しています。私はその行動を望んでいません。ランクを計算して割り当てるためのきれいな方法はありますか? r変数は(実際のコードで)foreachループが存在するのと同じスコープにありません。 var first

答えて

5
var first = myArray.Select((s, i) => { s.Rank = i; return s; }); 
+1

+1ですが、まだ 's'を返す必要がありますか? – Cameron

+0

+1、ありがとうございます –

+0

これはうまくいきました!ありがとう。私はどこから来たのですか? – Ankush

3

LINQは遅延評価を使用し、myArrayを使用するたびにSelect部分を実行します。

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

変更

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

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

にもう一つの方法は、あなたが使うべきではありません。この

var first = myArray.Zip(Enumerable.Range(0, int.MaxValue), (s, r) => 
{ 
    s.Rank = r; 
    return s; 
}); 
+0

ありがとう。うん、これは動作します。しかし、すべてのものをリストに変換するのではなく、その実行時に遅延実行とランク付けを行うためのクリーンな方法があります。 – Ankush

1

のように、毎回Zip使用して、新しい配列にmyArrayに参加するだろうコレクションに問い合わせていない場合は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++; 
} 
関連する問題