2015-10-15 40 views
3

我嘗試從一個字符串列表中一次取3行,但它不按預期工作。考慮下面的代碼...爲什麼這個可枚舉的列表分裂了?

var listOfStrings = new List<string> 
{ 
    "String 1", 
    "String 2", 
    "String 3", 
    "String 4", 
    "String 5", 
    "String 6" 
}; 

foreach (var x in listOfStrings.Take(3).ToList()) 
{ 
    var currRows = x.ToList(); 

    // currRows should have 3 items 
    foreach (var itm in currRows) 
    { 

    } 
} 

第一運行我期望currRows有3項(字符串1,2和3),第二時間我期望有這些3項(字符串4,5和6) 。但是當我運行這currRows只包含例如「字符串1」,這是逐字符分裂?!

我在這裏錯過了什麼?

+0

這不是'Take'的工作方式。或者任何其他LINQ操作員,真的 - 他們從不*修改*原始集合。您需要使用例如「Take」和「Skip」的組合。 – Luaan

+5

用'foreach(var itm in x)'替換你的第二個循環。不要在字符串上調用'ToList()',因爲它也是'IEnumerable ',所以'string.ToList()'返回一個字符列表。其次,在第一個循環中刪除「ToList()」調用,它什麼都不做,並且浪費了CPU和內存。最後,'Take(3)'只會將***前3個項目***,而不是3個。 – Rob

回答

2

但是當我運行這個currRows僅包含如「串1」和 這是由性格分裂性格?

這是因爲Enumerable.Take將採取從IEnumerable<T>請求的項目數量。這使得您的x變量的類型爲string,您稍後調用ToList(),有效創建List<char>,這不是您想要的。

您可以使用MoreLINQ其中有一個Batch擴展方法,它正是你想要的。它返回一個IEnumerable<IEnumerable<T>>

foreach (var batch in listOfStrings.Batch(3)) 
{ 
    // batch is an IEnumerable<T>, and will have 3 items. 
    foreach (var item in batch) 
    { 

    } 
} 

另一種可能性是自己創建該擴展方法。這是從this answer採取:

public static class EnumerableExtensions 
{ 
    public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> items, 
                 int maxItems) 
    { 
     return items.Select((item, inx) => new { item, inx }) 
        .GroupBy(x => x.inx/maxItems) 
        .Select(g => g.Select(x => x.item)); 
    } 
} 
+1

謝謝,MoreLinq確實非常方便。並感謝解釋爲什麼它不能如我所料。 – MTplus

2
  1. x.ToList();正在調用string上的方法。 A stringIEnumerable<char>,所以currRows的結果是一個字符列表。您可以完全刪除該行,並在第二個循環中使用x
  2. 如果您在foreach循環中使用的集合上使用ToList()通常是[1]毫無意義的操作。它會迭代你的集合並構造一個新的列表,然後迭代。你可以從你的第一個循環中刪除ToList,它會表現更好,但結果相同。
  3. Take只需要n件數,它不會被n項組分組。

試試這個:

var listOfStrings = new List<string> 
{ 
    "String 1", 
    "String 2", 
    "String 3", 
    "String 4", 
    "String 5", 
    "String 6" 
}; 

int step = 0; 
const int numTake = 3; 
for(var i = 0; i < listOfStrings.Count/numTake; i++) 
{ 
    Console.WriteLine("Starting a group!"); 
    foreach (var x in listOfStrings.Skip(3 * step++).Take(3)) 
    { 
     Console.WriteLine(x); 
    } 
} 

的房間數額巨大改善,但它應該給你的,你應該如何處理這項任務的想法。

  1. 箱子,你需要做到這一點 - 但你使用LINQ開始出來的時候很可能不會遇到他們。
0

與您的代碼開始:

var listOfStrings = new List<string> 
{ 
    "String 1", 
    "String 2", 
    "String 3", 
    "String 4", 
    "String 5", 
    "String 6" 
}; 

foreach (var x in listOfStrings.Take(3).ToList()) 
{ 
    var currRows = x.ToList(); 

    // currRows should have 3 items 
    foreach (var itm in currRows) 
    { 

    } 
} 

讓我們通過創建一個額外的變量簡化代碼一點點你正在遍歷:

var listOfStrings = new List<string> 
{ 
    "String 1", 
    "String 2", 
    "String 3", 
    "String 4", 
    "String 5", 
    "String 6" 
}; 

var thingsYouAreLoopingOver = listOfStrings.Take(3).ToList(); 

foreach (var x in thingsYouAreLoopingOver) 
{ 
    var currRows = x.ToList(); 

    // currRows should have 3 items 
    foreach (var itm in currRows) 
    { 

    } 
} 

但肯定這可以再次簡化爲東西YouAreLoopingOver只是listOfStrings的前三件事情,所以我們有:

var thingsYouAreLoopingOver = new List<string> 
{ 
    "String 1", 
    "String 2", 
    "String 3" 
}; 

foreach (var x in thingsYouAreLoopingOver) 
{ 
    var currRows = x.ToList(); 

    // currRows should have 3 items 
    foreach (var itm in currRows) 
    { 

    } 
} 

現在應該清楚爲什麼你會看到你所看到的行爲。