Группа linq смежными блоками

Скажем, у меня есть следующие данные:

Статус времени
10:00 На сайте 11:00 Off
12:00 Off
13:00 Off
14:00 Off
15:00 На сайте 16:00 Вкл.

Как я мог бы группировать это с помощью Linq во что-то вроде

[Вкл., [10:00]], [Выкл., [11:00, 12:00, 13:00, 14:00]], [Вкл., [15:00, 16:00]]

Ответ 1

Создайте расширение GroupAdjacent, например, перечисленное здесь.

И тогда это так же просто, как:

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

Ответ 2

Вы также можете сделать это с помощью одного запроса 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);

В основном он назначает ключ для каждого элемента, который увеличивается, когда текущий элемент не соответствует предыдущему элементу. Конечно, это предполагает, что ваши данные находятся в списке или массиве, иначе вам придется попробовать другой метод.

Ответ 3

Вот хардкорное решение 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 => e.x));

Ответ 4

Это можно сделать как.

  • Итерации по коллекции.
  • Использовать условие TakeWhile<Predicate> - это текст первого элемента коллекции On или Off.
  • Итерации по подмножеству из пункта 1 и повторение выше шага и конкатенация строки.

Надеюсь, что это поможет.

Ответ 5

Вы можете разобрать список и назначить смежный ключ, например, определить класс:

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

Вы присваиваете значения непрерывному ключу путем циклического перехода, поддерживая подсчет и обнаруживая, когда статус изменяется с "Вкл." на "Выкл." и т.д., который предоставит вам следующий список:

List<TimeStatus> timeStatuses = new List<TimeStatus> 
            {
                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"}
            };

Затем, используя следующий запрос, вы можете извлечь статус и сгруппировать Times:

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