我有一個簡單的類Item:
publicclass Item
{
public int Start { get; set; }
public int Stop { get; set; }
}
給定一個List<Item>,我想把它分成多個連續元素的子串列。 例如,一個方法
List<Item[]> GetContiguousSequences(Item[] items)
回傳串列的每個元素應該是一個Item的陣列,這樣list[i].Stop == list[i 1].Start每個元素
例如:
{[1,10] 。[10,11], [11,20] 。[25,30], [31,40] 。[40,45], [45,100]}。
=>
{{[1,10] 。[10,11], [11,20]}, {[25,30]}, {[31,40] 。 [40,45],[45,100]}}
下面是一個簡單的(并不保證沒有錯誤)實作,它只是簡單地走動輸入資料,尋找不連續的地方:
List<Item[]> GetContiguousSequences(Item [] items)
{
var ret = new List<Item[]>()。
var i1 = 0;
for(var i2=1; i2<items.Length; i2)
{
//discontinuity[/span]。
if(items[i2-1].stop != items[i2].Start)
{
var num = i2 - i1。
ret.Add(items.Skip(i1).Take(num).ToArray() )。
i1 = i2。
}
}
//end of array
ret.Add(items.Skip(i1).Take(items.Length-i1).ToArray())。
return ret;
}
這不是最直觀的實作,我想知道是否有辦法有一個更整潔的基于LINQ的方法。我正在研究Take和TakeWhile,想找到發生不連續的索引,但是沒有看到一個簡單的方法來做到這一點。
是否有一種簡單的方法來使用IEnumerable LINQ演算法,以一種更具描述性(不一定是性能)的方式來完成這個任務?
我在這里設定了一個簡單的測驗案例。https://dotnetfiddle.net/wrIa2J
uj5u.com熱心網友回復:
我真的不確定這是否比你原來的要好得多,但為了另一個解決方案的目的,一般的程序是
使用Select來投射出一個串列,并進行分組
GroupBy對上述內容進行分組Select將分組后的專案投射到一個ItemToList將結果投射到一個串列public static List<Item[]> GetContiguousSequences2(Item[]items
{
var currIdx = 1;
return items.Select( ( item,index) => new {
item = item,
index = index == 0 || items[index-1] .Stop == item.Start ? currIdx : currIdx
})
.GroupBy(x => x.index, x => x.item)
.Select(x => x.ToArray())
.ToList()。
}
實時示例。https://dotnetfiddle.net/mBfHru
另一種方法是使用Aggregate做一個聚合。這意味著維護一個最終的Result串列和一個Curr串列,在這里你可以聚合你的序列,當你發現不連續的時候將它們添加到Result串列中。這個方法看起來更接近于你的原始方法
public static List<Item[]> GetContiguousSequences3(Item []items)
{
var res = items. Aggregate(new {Result = new List<Item[]>(), Curr = new List< Item> ()}, (agg, item) => {
if(!agg.Curr.Any() || agg.Curr.Last().stop == item.Start) {
agg.Curr.Add(item)。
} else {
agg.Result.Add(agg.Curr.ToArray())。
agg.Curr.Clear()。
agg.Curr.Add(item)。
}
return agg;
});
res.Result.Add(res.Curr.ToArray()); //記得添加最后一個組。
return res.Result;
}
實時示例。https://dotnetfiddle.net/HL0VyJ
uj5u.com熱心網友回復:
你可以將ContiguousSplit作為一個corutine來實作:讓我們在source上回圈,并將item添加到current范圍,或者回傳它并開始一個新范圍。
private static IEnumerable<Item[]> ContiguousSplit(IEnumerable<Item> source){
List<Item> current = new List<Item>()。
foreach (var item in source) {
if (current.Count > 0 && current[current.Count - 1].stop != item.Start) {
yield return current.ToArray() 。
current.Clear()。
}
current.Add(item);
}
if (current.Count > 0)
yield return current.ToArray()。
}
然后,如果你想實作物化
List<Item[]> GetContiguousSequences(Item []items) => ContiguousSplit(items).ToList() 。
uj5u.com熱心網友回復:
你的解決方案是可以的。我認為在這種情況下,LINQ并沒有增加任何簡化或清晰性。這里有一個我覺得很直觀的快速解決方案:
static List<Item[]> GetContiguousSequences(Item[] items
{
var result = new List<Item[]>()。
int start = 0;
while (start < items.Length) {
int end = start 1;
while (end < items.Length && items[end].Start == items[end - 1].Stop) {
end ;
}
int len = end - start;
var a = new Item[len] 。
Array.Copy(items, start, a, 0, len);
result.Add(a);
start = end;
}
return result;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/310088.html
標籤:
