Группировать список объектов на основе отметки времени - PullRequest
2 голосов
/ 15 марта 2020

Имея следующий интерфейс:

public class foo
{
    [Key]
    public int Id { get; set; }}
    public string Notes { get; set; }
    public DateTime? Timestamp { get; set; }
}

Использование контекста данных, например: await context.foos.ToListAsync() возвращает полный список записей. Цель, которую я хочу достичь, - это реструктурированный объект JSON с тем же откликом, что и ниже:

[
    {
        year: YYYY,
        count: 0, // <- total `foos` in year
        months: [
            {
                month: 'January',
                count: 0, // <- total `foos` in month
                days: [
                    {
                        day: 0,
                        count: 0, // <- total `foos` in day
                        foos: [
                            {
                                Id: 0,
                                Notes: '...',
                                Timestamp: '...'
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

Я смог достичь этого с помощью нескольких вложенных циклов for. Однако это кажется очень плохим подходом, поскольку вложенные циклы увеличивают время процесса в геометрической прогрессии.

Есть ли какой-нибудь способ достичь этого с помощью LINQ? Или, может быть, более эффективное решение?

Ответы [ 2 ]

2 голосов
/ 15 марта 2020

Есть ли способ достичь этого с помощью LINQ?

Записи могут быть сгруппированы с помощью соответствующей клавиши

//entries => List<foo>

var result = entries
    .GroupBy(_ => _.Timestamp?.Year) //Group all foo by year
    .Select(years => new { 
        year = years.Key, //YYYY
        count = years.Count(), // total `foos` in year
        months = years
            .GroupBy(_ => _.Timestamp?.Month) //Group all foo in this group by month
            .Select(months => new {
                month = months.First().Timestamp?.ToString("MMMM"), //January
                count = months.Count(),  // total `foos` in month
                days = months
                    .GroupBy(_ => _.Timestamp?.Day) //group all foo in this group by day
                    .Select(days => new {
                        day = days.Key,
                        count = days.Count(), // total `foos` in day
                        foos = days.ToArray()
                    }).ToArray()
            }).ToArray()
    });

Ссылка Linq: GroupBy

Ссылка Результаты группового запроса

2 голосов
/ 15 марта 2020

Алгоритмически, и это не имеет отношения к языку, который вы используете, вы можете сделать что-то вроде этого псевдокода:

for (item in listOfItems) {
    year = getYearFromItem(item)
    month = getMonthFromItem(item)
    day = gteDayFromItem(item)

    updateYears(data, year)
    updateMonth(data, month)
    updateDay(data, day)
}

Вы будете просматривать данные ровно один раз и создание year/month/day подобъектов как вы go.

...