2014-03-07 75 views
1

以下是我想分組的數據。如何在LINQ中對範圍進行分組

Start  End 
    2   4 
    26  30 
    5   9 
    20  24 
    18  19 

因爲我有18 - 19和20 - 24我想添加這兩個一起爲18 - 24。在這種情況下的規則(A,B)=> b.start - a.end = 1和結果將是

Start  End 
    18  24 
    2   9 
    26  30 

編輯添加了每條評論下面的最後結果行。

+0

LINQ-To-What?你在使用數據庫嗎? –

+0

@TimSchmelter right,LINQ to Objects –

+3

你可以用聚合來完成它,但假設你沒有使用數據庫並且可以做你喜歡的事情,我可能會寫一個自定義的操作符,它。基本上你想要按照順序對這些進行排序,然後根據需要使用前瞻合併範圍來遍歷列表。 – Rup

回答

5

所以我們將從一個名爲GroupWhile的幫助方法開始。它將提供一個謂詞,接受來自序列,前一個和當前序列的兩個項目。如果該謂詞返回true,則當前項目與前一個項目進入相同的組。如果不是,則啓動一個新組。

public static IEnumerable<IEnumerable<T>> GroupWhile<T>(
    this IEnumerable<T> source, Func<T, T, bool> predicate) 
{ 
    using (var iterator = source.GetEnumerator()) 
    { 
     if (!iterator.MoveNext()) 
      yield break; 

     List<T> list = new List<T>() { iterator.Current }; 

     T previous = iterator.Current; 

     while (iterator.MoveNext()) 
     { 
      if (!predicate(previous, iterator.Current)) 
      { 
       yield return list; 
       list = new List<T>(); 
      } 

      list.Add(iterator.Current); 
      previous = iterator.Current; 
     } 
     yield return list; 
    } 
} 

一旦我們有了這一點,我們可以開始訂購商品,然後結束日期,組他們,而先前的範圍的結束與下一個範圍的開始重疊,然後摺疊每個組成一種新的基於範圍關於組的開始和結束值。

var collapsedRanges = ranges.OrderBy(range => range.Start) 
    .ThenBy(range => range.End) 
    .GroupWhile((prev, cur) => prev.End + 1 >= cur.Start) 
    .Select(group => new Range() 
    { 
     Start = group.First().Start, 
     End = group.Select(range => range.End).Max(), 
    }); 
相關問題