2010-09-22 75 views
3

我有一個List<T>,它是'常規'元素和'標記'元素的混合物。我想把它分成一個List<List<T>>,在標記處斷開。使用LINQ標記元素的分割列表?

例如給出{a,b,M,c,d,e,f,M,g}的輸入,其中'M'是一個標記元素,我想得到{{a,b},{c,d,e ,f},{g}}

使用循環很容易完成這項工作,但似乎應該可以使用LINQ更緊湊地表達它,並且在一些頭部劃傷之後,我可以看不出來。 (沒有足夠的LINQ福,我猜。)

回答

5

嗯......

varSplitList = myList.Aggregate(new List<List<T>>{new List<T>()}, 
    (sl,t)=> { 
     if(/*T is a marker element*/) sl.Add(new List<T>()); 
     else sl.Last().Add(t); 
     return sl; 
    }); 

有可能是一個更可讀的方式,但應該工作。聚集是一種非常強大的「系列計算」方法,對於這些類型的東西很有用。你爲它提供了一個「種子」(在這個例子中是一個帶有單個子列表的新列表),並且爲源中的每個元素執行操作,該操作接受種子和當前元素並返回(可能是修改過的)種子,然後傳遞給下一個元素的操作。

作爲簡單的例子,這裏有一個階乘計算器中的LINQ:

long fact = Enumerable.Range(1,n).Aggregate(1, (f,n)=>f*n));

Enumerable.Range()產生的整數範圍從1到n。聚合函數從1開始,並且對於每個元件,乘以該元件的種子:

1 * 1 = 1 1 * 2 = 2 2 * 3 = 6 6 * 4 = 24 24 * 5 = 120 ...

最後,fact在完成所有計算後給出種子的值。

+2

我給你的風格點(和給予好評),但我要說的是,這並不比等效循環實現更緊湊 - 它幾乎就是LINQ服裝中的循環。 – McKenzieG1 2010-09-22 20:04:53

+0

非常真實的......實際上所有的LINQ方法。嚴重的是,LINQ是一個迭代器 - 隱藏器的庫。 – KeithS 2010-09-22 20:23:24

2

似乎不像LINQ的工作。但是如果我將它寫沒有「在LINQ服裝圈」寫作,我會做這樣的事情:

var list = new List<char> {'a', 'b', 'M', 'c', 'd', 'e', 'f', 'M', 'g'}; 
const char marker = 'M'; 

var markerIndexes = list.Select((c, i) => new { c, i }).Where(z => z.c == marker).Select(z => z.i); 
var split = from z in list.Select((c, i) => new { c, i }) 
      where z.c != marker 
      group z.c by markerIndexes.Count(mi => z.i > mi) into g 
      select g.ToList(); 
return split.ToList(); 
+0

相當巧妙,但也(矛盾地?)有點可怕。當然比普通的循環實現更難以理解,並且不再簡潔。根據目前的答案,看起來你是對的 - 「看起來不像LINQ的工作」。但是我從研究答案中學到了一些東西 - 謝謝。 – McKenzieG1 2010-09-22 20:44:21