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));
它可以作为。
- 迭代收集。
- 使用
TakeWhile
条件是集合的第一个元素On或Off的文本。 - 迭代第一点的子集并重复上面的步骤并连接字符串。
希望能帮助到你..
您可以解析列表并分配一个连续的键,例如定义一个类:
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 });