linq group by contiguous blocks

假设我有以下数据:

时间状态
10:00开
11:00关闭
12:00关闭
13:00关闭
14:00关闭
15:00开
16:00开

我如何使用Linq将其分组

[开,[10:00]],[关闭,[11:00,12:00,13:00,14:00]],[开启,[15:00,16:00]]

创建GroupAdjacent扩展名,例如此处列出的扩展名。

然后它就像这样简单:

 var groups = myData.GroupAdjacent(data => data.OnOffStatus); 

您也可以使用一个Linq查询使用变量来跟踪更改,如下所示。

 int key = 0; var query = data.Select( (n,i) => i == 0 ? new { Value = n, Key = key } : new { Value = n, Key = n.OnOffFlag == data[i - 1].OnOffFlag ? key : ++key }) .GroupBy(a => a.Key, a => a.Value); 

基本上,它为每个项目分配一个键,当当前项目不等于前一项目时,该项目会增加。 当然,这假设您的数据位于List或Array中,否则您必须尝试不同的方法

这是一个硬核 LINQ解决方案,使用Enumerable.Zip来比较连续的元素并生成一个连续的键:

 var adj = 0; var t = data.Zip(data.Skip(1).Concat(new TimeStatus[] { null }), (x, y) => new { x, key = (x == null || y == null || x.Status == y.Status) ? adj : adj++ } ).GroupBy(i => i.key, (k, g) => g.Select(e => ex)); 

它可以作为。

  1. 迭代收集。
  2. 使用TakeWhile条件是集合的第一个元素On或Off的文本。
  3. 迭代第一点的子集并重复上面的步骤并连接字符串。

希望能帮助到你..

您可以解析列表并分配一个连续的键,例如定义一个类:

 public class TimeStatus { public int ContiguousKey { get; set; } public string Time { get; set; } public string Status { get; set; } } 

您可以通过循环,维护计数以及检测状态何时从开启​​变为关闭等来为连续键分配值,这样就可以得到如下列表:

 List timeStatuses = new List { new TimeStatus { ContiguousKey = 1, Status = "On", Time = "10:00"}, new TimeStatus { ContiguousKey = 1, Status = "On", Time = "11:00"}, new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "12:00"}, new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "13:00"}, new TimeStatus { ContiguousKey = 2, Status = "Off", Time = "14:00"}, new TimeStatus { ContiguousKey = 3, Status = "On", Time = "15:00"}, new TimeStatus { ContiguousKey = 3, Status = "On", Time = "16:00"} }; 

然后使用以下查询,您可以提取状态和分组时间:

  var query = timeStatuses.GroupBy(t => t.ContiguousKey) .Select(g => new { Status = g.First().Status, Times = g });