2012-04-28 50 views
0

我想計算IEnumerable列表中的元素的排名並將其分配給成員。但下面的代碼僅在第一次調用時才起作用。第二次通話從最後一個等級值開始。因此,而不是輸出012和012,我得到012和345如何計算IEnumerable的排名<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被捕獲(關閉),並重新使用所謂的第二次時。我不想要那種行爲。有沒有乾淨的方法來計算等級並分配它? 另外r變量(在實際代碼中)不在foreach循環存在的相同範圍內。它在一個函數中返回var first

回答

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

+1,但你仍然應該返回's',不是嗎? – Cameron 2012-04-28 13:52:59

+0

+1,謝謝你的提示 – 2012-04-28 13:56:10

+0

這個工作!謝謝。我從哪裏來? – Ankush 2012-04-28 13:57:08

3

LINQ每次使用myArray時都使用懶惰評估並運行Select部件。

通過將結果存儲在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; 
}); 
+0

感謝。這是可行的。但有沒有任何干淨的方式來延遲執行和排序生成的,而不是將整個事情轉換爲列表。 – Ankush 2012-04-28 13:52:44

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++; 
} 
相關問題