Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

linq group by contiguous blocks

Tags:

c#

linq

Let's say I have following data:

Time Status
10:00 On
11:00 Off
12:00 Off
13:00 Off
14:00 Off
15:00 On
16:00 On

How could I group that using Linq into something like

[On, [10:00]], [Off, [11:00, 12:00, 13:00, 14:00]], [On, [15:00, 16:00]]

like image 275
Giedrius Avatar asked Feb 07 '13 10:02

Giedrius


3 Answers

Create a GroupAdjacent extension, such as the one listed here.

And then it's as simple as:

var groups = myData.GroupAdjacent(data => data.OnOffStatus);
like image 68
Ani Avatar answered Sep 30 '22 17:09

Ani


You could also do this with one Linq query using a variable to keep track of the changes, like this.

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);

Basically it assigns a key for each item that increments when the current item does not equal the previous item. Of course this assumes that your data is in a List or Array, otherwise you'd have to try a different method

like image 38
juharr Avatar answered Sep 30 '22 18:09

juharr


Here is a hardcore LINQ solution by using Enumerable.Zip to compare contiguous elements and generate a contiguous key:

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 => e.x));
like image 27
Oleks Avatar answered Sep 30 '22 18:09

Oleks