Группировка по дате в пределах определенного диапазона - PullRequest
0 голосов
/ 10 октября 2018

Допустим, у меня есть следующая коллекция предметов и дат в памяти:

ItemID: 1, Date: 10/10/2018 11:30 AM
ItemID: 1, Date: 10/10/2018 11:32 AM
ItemID: 1, Date: 10/10/2018 11:33 AM
ItemID: 1, Date: 10/10/2018 11:34 AM
ItemID: 1, Date: 10/10/2018 11:57 AM
ItemID: 2, Date: 10/10/2018 7:45 AM
ItemID: 2, Date: 10/10/2018 7:49 AM
ItemID: 3, Date: 10/10/2018 8:45 AM
ItemID: 3, Date: 10/10/2018 9:13 AM

Я бы хотел сгруппировать по ItemID и Date, но по датам, которые я хочу, сгруппировать по тем, которые попадают в 5 минут наименьшей даты, в данном случае для элемента 1 самое низкое время: 11:30, поэтому сгруппируйте все, что попадает между следующими минутами 11:30 + 5 минут

В приведенном выше наборе данных будут сгруппированы следующие данные:

ItemID: 1, Date: 10/10/2018 11:30 AM    <-- Grouped with Item 1
ItemID: 1, Date: 10/10/2018 11:32 AM    <-- Grouped with Item 1
ItemID: 1, Date: 10/10/2018 11:33 AM    <-- Grouped with Item 1
ItemID: 1, Date: 10/10/2018 11:34 AM    <-- Grouped with Item 1


ItemID: 1, Date: 10/10/2018 11:57 AM    <-- Not Grouped


ItemID: 2, Date: 10/10/2018 7:45 AM    <-- Grouped with Item 2
ItemID: 2, Date: 10/10/2018 7:49 AM    <-- Grouped with Item 2


ItemID: 3, Date: 10/10/2018 8:45 AM    <-- Not Grouped

ItemID: 3, Date: 10/10/2018 9:13 AM    <-- Not Grouped

Сгруппированы те, которые находятся в пределах 5 минут друг от друга.

ВЫХОД:

Item 1:
Date: 10/10/2018 11:30 AM    <--- Lowest Minute is 30 so 30 + 5 range group
Date: 10/10/2018 11:32 AM
Date: 10/10/2018 11:33 AM
Date: 10/10/2018 11:34 AM

Item 1:
Date: 10/10/2018 11:57 AM

Item 2:
Date: 10/10/2018 7:45 AM
Date: 10/10/2018 7:49 AM

Item 3:
Date: 10/10/2018 8:45 AM

Item 3:
Date: 10/10/2018 9:13 AM

Ответы [ 3 ]

0 голосов
/ 10 октября 2018

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

var interval = 5;
var groupedItems = items
    .GroupBy(i => i.ItemId, (k, g) => g
        .GroupBy(i => (long)(i.Date - g.Min(e => e.Date)).TotalMinutes / interval))
    .SelectMany(g => g);
0 голосов
/ 11 октября 2018

Вот полнофункциональный рабочий пример того, как решить эту проблему в соответствии с двумя предыдущими ответами.Просто откройте VS и создайте новое ConsoleApp, вставьте его и попробуйте.Надеюсь, что вы найдете свой путь через это сейчас.

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp3
{
    public class Item
    {
        public int ItemID { get; set; }
        public DateTime Date { get; set; }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<Item> items = new List<Item>
            {
                new Item { ItemID= 1, Date = new DateTime(2018, 10, 10, 11, 30, 0) },
                new Item { ItemID= 1, Date = new DateTime(2018, 10, 10, 11, 32, 0) },
                new Item { ItemID= 1, Date = new DateTime(2018, 10, 10, 11, 33, 0) },
                new Item { ItemID= 1, Date = new DateTime(2018, 10, 10, 11, 34, 0) },
                new Item { ItemID= 1, Date = new DateTime(2018, 10, 10, 11, 57, 0) },
                new Item { ItemID= 2, Date = new DateTime(2018, 10, 10, 7, 45, 0) },
                new Item { ItemID= 2, Date = new DateTime(2018, 10, 10, 7, 49, 0) },
                new Item { ItemID= 2, Date = new DateTime(2018, 10, 10, 8, 45, 0) },
                new Item { ItemID= 2, Date = new DateTime(2018, 10, 10, 9, 13, 0) }
            };

            var groupedItems = items.GroupBy(i => i.ItemID, (k, g) => g
          .GroupBy(i => (long)new TimeSpan(i.Date.Ticks - g.Min(e => e.Date).Ticks).TotalMinutes / 5));

            var groupIndex = 0;
            foreach (var group in groupedItems)
            {
                foreach (IGrouping<long, Item> groupItem in group)
                {
                    Console.Out.WriteLine("Group " + (++groupIndex));

                    foreach (var item in groupItem)
                    {
                        Console.WriteLine($"Item {item.ItemID}. Date: {item.Date}");

                    }
                    Console.Out.WriteLine();
                }
            }
            Console.ReadLine();
        }
    }
}

Приветствия

0 голосов
/ 10 октября 2018

Вот очень грубый пример, который я собрал, чтобы получить желаемый «результат».Конечно, примените это к вашей ситуации и добавьте свою собственную проверку ошибок / валидацию / упорядочение / и т.д. Я также не использовал LINQ, так как не чувствовал, что это уместно для вашего комментария .Наконец, я не совсем соответствовал вашему выводу.Я чувствую, что это может быть для назначения какого-то рода.Если это так, то вы, безусловно, можете выполнить эту небольшую настройку.

Класс поддержки:

class Item
{
    public int ItemID { get; set; }
    public DateTime Date { get; set; }
}

Пример метода:

private static void Example()
{
    var myList = new List<Item>
    {
        new Item {ItemID = 1, Date = DateTime.Parse("10/10/2018 11:30 AM") },
        new Item {ItemID = 1, Date = DateTime.Parse("10/10/2018 11:32 AM") },
        new Item {ItemID = 1, Date = DateTime.Parse("10/10/2018 11:33 AM") },
        new Item {ItemID = 1, Date = DateTime.Parse("10/10/2018 11:34 AM") },
        new Item {ItemID = 1, Date = DateTime.Parse("10/10/2018 11:57 AM") },
        new Item {ItemID = 2, Date = DateTime.Parse("10/10/2018 7:45 AM") },
        new Item {ItemID = 2, Date = DateTime.Parse("10/10/2018 7:49 AM") },
        new Item {ItemID = 3, Date = DateTime.Parse("10/10/2018 8:45 AM") },
        new Item {ItemID = 3, Date = DateTime.Parse("10/10/2018 9:13 AM") }
    };

    Item baseItem = myList.First();
    int currentGroup = 1;

    // output first group
    Console.WriteLine($"Group {currentGroup}");

    foreach (var item in myList) // .OrderBy(i=>i.ItemID).ThenBy(i => i.Date))
    {
        // if item is different OR date is >5mins from the first
        if (item.ItemID != baseItem.ItemID || item.Date > baseItem.Date.AddMinutes(5))
        {
            // different group
            currentGroup += 1;

            // set new base item
            baseItem = item;

            Console.WriteLine($"\nGroup {currentGroup}");// output new group
        }

        // output the item
        Console.WriteLine($"Item {item.ItemID}. Date: {item.Date}");
    }
}

Вывод:

Group 1
Item 1. Date: 10/10/2018 11:30:00 AM
Item 1. Date: 10/10/2018 11:32:00 AM
Item 1. Date: 10/10/2018 11:33:00 AM
Item 1. Date: 10/10/2018 11:34:00 AM

Group 2
Item 1. Date: 10/10/2018 11:57:00 AM

Group 3
Item 2. Date: 10/10/2018 7:45:00 AM
Item 2. Date: 10/10/2018 7:49:00 AM

Group 4
Item 3. Date: 10/10/2018 8:45:00 AM

Group 5
Item 3. Date: 10/10/2018 9:13:00 AM
...