也就是說是什麼郵政編碼爲。
var result = FirstNames
.Zip(LastNames, (f,l) => new {f,l})
.Zip(BirthDates, (fl, b) => new {First=fl.f, Last = fl.l, BirthDate = b});
關於縮放:
int count = 50000000;
var FirstNames = Enumerable.Range(0, count).Select(x=>x.ToString());
var LastNames = Enumerable.Range(0, count).Select(x=>x.ToString());
var BirthDates = Enumerable.Range(0, count).Select(x=> DateTime.Now.AddSeconds(x));
var sw = new Stopwatch();
sw.Start();
var result = FirstNames
.Zip(LastNames, (f,l) => new {f,l})
.Zip(BirthDates, (fl, b) => new {First=fl.f, Last = fl.l, BirthDate = b});
foreach(var r in result)
{
var x = r;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds); // Returns 69191 on my machine.
雖然這些炸燬帶出的存儲器:
int count = 50000000;
var FirstNames = Enumerable.Range(0, count).Select(x=>x.ToString());
var LastNames = Enumerable.Range(0, count).Select(x=>x.ToString());
var BirthDates = Enumerable.Range(0, count).Select(x=> DateTime.Now.AddSeconds(x));
var sw = new Stopwatch();
sw.Start();
var FirstNamesList = FirstNames.ToList(); // Blows up in 32-bit .NET with out of Memory
var LastNamesList = LastNames.ToList();
var BirthDatesList = BirthDates.ToList();
var result = Enumerable.Range(0, FirstNamesList.Count())
.Select(i => new
{
First = FirstNamesList[i],
Last = LastNamesList[i],
Birthdate = BirthDatesList[i]
});
result = BirthDatesList.Select((bd, i) => new
{
First = FirstNamesList[i],
Last = LastNamesList[i],
BirthDate = bd
});
foreach(var r in result)
{
var x = r;
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
在較低的值時,將所述可枚舉的列表的費用是昂貴得多而不是附加的對象創建。 Zip比索引版本快大約30%。隨着您添加更多列,Zips的優勢可能會縮小。
性能特徵也有很大不同。 Zip例程幾乎立即開始輸出答案,其他人將只在整個Enumerables已被閱讀並轉換爲列表後纔開始輸出答案,因此如果您使用.Skip(x).Take(y)
獲取結果並對其進行分頁,或者檢查是否存在某個問題.Any(...)
它會更快,因爲它不需要轉換整個枚舉。
最後,如果它成爲性能的關鍵,你需要實現很多的效果,你可以考慮延長壓縮處理可枚舉像一個任意數(從喬恩斯基特無恥地竊取 - https://codeblog.jonskeet.uk/2011/01/14/reimplementing-linq-to-objects-part-35-zip/):
private static IEnumerable<TResult> Zip<TFirst, TSecond, TThird, TResult>(
IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
IEnumerable<TThird> third,
Func<TFirst, TSecond, TThird, TResult> resultSelector)
{
using (IEnumerator<TFirst> iterator1 = first.GetEnumerator())
using (IEnumerator<TSecond> iterator2 = second.GetEnumerator())
using (IEnumerator<TThird> iterator3 = third.GetEnumerator())
{
while (iterator1.MoveNext() && iterator2.MoveNext() && iterator3.MoveNext())
{
yield return resultSelector(iterator1.Current, iterator2.Current, iterator3.Current);
}
}
}
然後,你可以這樣做:
var result = FirstNames
.Zip(LastNames, BirthDates, (f,l,b) => new {First=f,Last=l,BirthDate=b});
現在你甚至不用中間對象被創建的問題,所以你得到了世界上最好的。
或者利用執行這裏處理任何數量一般:Zip multiple/abitrary number of enumerables in C#
我最初在出現這個問題時使用'Zip'進行了研究。我認爲我同意你的看法,但你認爲這個解決方案可以擴展嗎?所有的答案表現非常相似,使用一個簡單的秒錶類。這將創建一個新名單和姓氏,然後是第一個/最後一個姓氏和生日的另一個。如果我們添加另一個說法,年齡列表,它是否會隨着這個方面進行擴展? –
@FusRoDah它將在很大程度上取決於消息來源以及數據的消耗方式。創建臨時對象的確需要一些性能(我相信),但是,如果源和/或消耗將從可枚舉的懶惰評估中受益,它可能會表現更好或更差,特別是因爲在最好的情況下,由於數據流式傳輸會需要更少的內存從一次一個來源,處理然後丟棄,而不是假設來源是可轉位的(或轉換成這樣的)。 –
感謝您詳細說明優缺點,並提供比較代碼。檢查「Any()」正是我們通用列表的最終產品所要做的。因此,我認爲你已經完全回答了我的問題。 –