我有一個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福,我猜。)
我有一個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福,我猜。)
嗯......
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
在完成所有計算後給出種子的值。
似乎不像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();
相當巧妙,但也(矛盾地?)有點可怕。當然比普通的循環實現更難以理解,並且不再簡潔。根據目前的答案,看起來你是對的 - 「看起來不像LINQ的工作」。但是我從研究答案中學到了一些東西 - 謝謝。 – McKenzieG1 2010-09-22 20:44:21
我給你的風格點(和給予好評),但我要說的是,這並不比等效循環實現更緊湊 - 它幾乎就是LINQ服裝中的循環。 – McKenzieG1 2010-09-22 20:04:53
非常真實的......實際上所有的LINQ方法。嚴重的是,LINQ是一個迭代器 - 隱藏器的庫。 – KeithS 2010-09-22 20:23:24