Linq,“分组依据”日期,月份
Linq, `Group By` Date, Month
我正在为 LINQ Group By 问题苦苦挣扎。
我有以下数据模型:
public sealed class Class
{
[Key]
public int Id { get; init; }
public IEnumerable<Person> Persons { get; init; } = null!;
}
public sealed class Person
{
[Key]
public int Id { get; init; }
public string Name { get; set; }
public DateTime RegistrationDate { get; set; }
public ulong FriendCount { get; set; }
public ulong ScoreCount { get; set; }
}
现在,我正在尝试构建一个查询,returns 我,针对单个 class,包含 12 个元素的集合(过去 12 个月中每个月一个),它显示了那个月所有人的“FriendCount”和“ScoreCount”的总和。
所以,这是我想要实现的目标:
[
{ date: 01/01/2021, friendCount: 0, scoreCount: 50 },
{ date: 01/02/2021, friendCount: 15, scoreCount: 50 },
...
]
LINQ(分组依据)表达式是否可行?
这是我根据日期时间过滤数据的结果。
public async Task<Class?> GetData(int id)
{
DateTime currentDateTime = this.dateTimeProvider.Now;
DateTime startDateTime = currentDateTime.RemoveMonths(12);
School? result = await this.context.Class.Include(static class => class.Persons)
.Where(class => class.Id == id)
.Select(
class => new Class
{
Id = class.Id,
Persons = class.Persons
.Where(person => person.RegistrationDate >= startDateTime && person.RegistrationDate <= currentDateTime)
// Here I believe something like a group by clausule should be added.
我不太确定你想要的输出如何适合你的 Class
/School
classes,所以我将提供一个只解决 Person
对象。希望你会发现有用。
对于 .GroupBy()
操作,您可以使用特定 Person
的 [=] 的 Year
和 Month
值创建新的 DateTime
23=] 并将其用作每个分组的 Key
.
我假设您的输出 class 可能如下所示:
public class MonthlyStats
{
public DateTime Date { get; set; }
public ulong FriendCount { get; set; }
public ulong ScoreCount { get; set; }
}
然后,分组和选择可以如下进行:
Person[] persons = { ... };
MonthlyStats[] monthlyStats = persons
.GroupBy(p => new DateTime(p.RegistrationDate.Year, p.RegistrationDate.Month, 1),
( firstDayOfMonth, personsInMonth ) => new MonthlyStats
{
Date = firstDayOfMonth,
FriendCount = (ulong)personsInMonth.Sum(p => (decimal)p.FriendCount),
ScoreCount = (ulong)personsInMonth.Sum(p => (decimal)p.ScoreCount)
})
.OrderBy(stat => stat.Date)
.ToArray();
如果persons
定义如下:
Person[] persons =
{
new(1, "A", new DateTime(2022, 1, 4), 9, 23),
new(2, "B", new DateTime(2021, 4, 8), 7, 29),
new(3, "C", new DateTime(2021, 9, 11), 4, 13),
new(4, "D", new DateTime(2021, 11, 1), 10, 14),
new(5, "E", new DateTime(2021, 4, 17), 12, 17),
new(6, "F", new DateTime(2022, 1, 27), 5, 11),
new(7, "G", new DateTime(2021, 9, 2), 13, 31),
};
,分组如下:
01.01.2022
(1, "A", DateTime(2022, 1, 4), 9, 23)
(6, "F", DateTime(2022, 1, 27), 5, 11)
01.04.2021
(2, "B", DateTime(2021, 4, 8), 7, 29)
(5, "E", DateTime(2021, 4, 17), 12, 17)
01.09.2021
(3, "C", DateTime(2021, 9, 11), 4, 13)
(7, "G", DateTime(2021, 9, 2), 13, 31)
01.11.2021
(4, "D", DateTime(2021, 11, 1), 10, 14)
生成的 MonthlyStats
个对象将是:
Date FC SC
---------------------------
01/04/2021 19 46
01/09/2021 17 44
01/11/2021 10 14
01/01/2022 14 34
示例 fiddle here.
更新 -- 总是 return 12 个月
要始终生成涵盖前一年跨度的每个完整月的集合,您可以首先生成“月份日期”的集合,然后利用 Enumerable.GroupJoin()
:
var startDate = new DateTime(DateTime.Today.Year - 1, DateTime.Today.Month, 1);
DateTime[] firstDayOfMonths = Enumerable.Range(0, 12)
.Select(i => new DateTime(startDate.AddMonths(i).Ticks))
.ToArray();
MonthlyStats[] monthlyStats = firstDayOfMonths
.GroupJoin(persons,
date => date,
person => new DateTime(person.RegistrationDate.Year, person.RegistrationDate.Month, 1),
( firstDayOfMonth, personsInMonth ) => new MonthlyStats
{
Date = firstDayOfMonth,
FriendCount = (ulong)personsInMonth.Sum(p => (decimal)p.FriendCount),
ScoreCount = (ulong)personsInMonth.Sum(p => (decimal)p.ScoreCount)
})
.ToArray();
使用相同的 persons
输入,输出现在如下所示:
01/04/2021 | 19 | 46
01/05/2021 | 0 | 0
01/06/2021 | 0 | 0
01/07/2021 | 0 | 0
01/08/2021 | 0 | 0
01/09/2021 | 17 | 44
01/10/2021 | 0 | 0
01/11/2021 | 10 | 14
01/12/2021 | 0 | 0
01/01/2022 | 14 | 34
01/02/2022 | 0 | 0
01/03/2022 | 0 | 0
(您可能需要调整 startDate
生成中的月份部分或 Enumerable.Range()
中的起始值,例如包括当前月份,如果这是您更喜欢的.)
示例 fiddle here.
我正在为 LINQ Group By 问题苦苦挣扎。 我有以下数据模型:
public sealed class Class
{
[Key]
public int Id { get; init; }
public IEnumerable<Person> Persons { get; init; } = null!;
}
public sealed class Person
{
[Key]
public int Id { get; init; }
public string Name { get; set; }
public DateTime RegistrationDate { get; set; }
public ulong FriendCount { get; set; }
public ulong ScoreCount { get; set; }
}
现在,我正在尝试构建一个查询,returns 我,针对单个 class,包含 12 个元素的集合(过去 12 个月中每个月一个),它显示了那个月所有人的“FriendCount”和“ScoreCount”的总和。
所以,这是我想要实现的目标:
[
{ date: 01/01/2021, friendCount: 0, scoreCount: 50 },
{ date: 01/02/2021, friendCount: 15, scoreCount: 50 },
...
]
LINQ(分组依据)表达式是否可行?
这是我根据日期时间过滤数据的结果。
public async Task<Class?> GetData(int id)
{
DateTime currentDateTime = this.dateTimeProvider.Now;
DateTime startDateTime = currentDateTime.RemoveMonths(12);
School? result = await this.context.Class.Include(static class => class.Persons)
.Where(class => class.Id == id)
.Select(
class => new Class
{
Id = class.Id,
Persons = class.Persons
.Where(person => person.RegistrationDate >= startDateTime && person.RegistrationDate <= currentDateTime)
// Here I believe something like a group by clausule should be added.
我不太确定你想要的输出如何适合你的 Class
/School
classes,所以我将提供一个只解决 Person
对象。希望你会发现有用。
对于 .GroupBy()
操作,您可以使用特定 Person
的 [=] 的 Year
和 Month
值创建新的 DateTime
23=] 并将其用作每个分组的 Key
.
我假设您的输出 class 可能如下所示:
public class MonthlyStats
{
public DateTime Date { get; set; }
public ulong FriendCount { get; set; }
public ulong ScoreCount { get; set; }
}
然后,分组和选择可以如下进行:
Person[] persons = { ... };
MonthlyStats[] monthlyStats = persons
.GroupBy(p => new DateTime(p.RegistrationDate.Year, p.RegistrationDate.Month, 1),
( firstDayOfMonth, personsInMonth ) => new MonthlyStats
{
Date = firstDayOfMonth,
FriendCount = (ulong)personsInMonth.Sum(p => (decimal)p.FriendCount),
ScoreCount = (ulong)personsInMonth.Sum(p => (decimal)p.ScoreCount)
})
.OrderBy(stat => stat.Date)
.ToArray();
如果persons
定义如下:
Person[] persons =
{
new(1, "A", new DateTime(2022, 1, 4), 9, 23),
new(2, "B", new DateTime(2021, 4, 8), 7, 29),
new(3, "C", new DateTime(2021, 9, 11), 4, 13),
new(4, "D", new DateTime(2021, 11, 1), 10, 14),
new(5, "E", new DateTime(2021, 4, 17), 12, 17),
new(6, "F", new DateTime(2022, 1, 27), 5, 11),
new(7, "G", new DateTime(2021, 9, 2), 13, 31),
};
,分组如下:
01.01.2022
(1, "A", DateTime(2022, 1, 4), 9, 23)
(6, "F", DateTime(2022, 1, 27), 5, 11)
01.04.2021
(2, "B", DateTime(2021, 4, 8), 7, 29)
(5, "E", DateTime(2021, 4, 17), 12, 17)
01.09.2021
(3, "C", DateTime(2021, 9, 11), 4, 13)
(7, "G", DateTime(2021, 9, 2), 13, 31)
01.11.2021
(4, "D", DateTime(2021, 11, 1), 10, 14)
生成的 MonthlyStats
个对象将是:
Date FC SC
---------------------------
01/04/2021 19 46
01/09/2021 17 44
01/11/2021 10 14
01/01/2022 14 34
示例 fiddle here.
更新 -- 总是 return 12 个月
要始终生成涵盖前一年跨度的每个完整月的集合,您可以首先生成“月份日期”的集合,然后利用 Enumerable.GroupJoin()
:
var startDate = new DateTime(DateTime.Today.Year - 1, DateTime.Today.Month, 1);
DateTime[] firstDayOfMonths = Enumerable.Range(0, 12)
.Select(i => new DateTime(startDate.AddMonths(i).Ticks))
.ToArray();
MonthlyStats[] monthlyStats = firstDayOfMonths
.GroupJoin(persons,
date => date,
person => new DateTime(person.RegistrationDate.Year, person.RegistrationDate.Month, 1),
( firstDayOfMonth, personsInMonth ) => new MonthlyStats
{
Date = firstDayOfMonth,
FriendCount = (ulong)personsInMonth.Sum(p => (decimal)p.FriendCount),
ScoreCount = (ulong)personsInMonth.Sum(p => (decimal)p.ScoreCount)
})
.ToArray();
使用相同的 persons
输入,输出现在如下所示:
01/04/2021 | 19 | 46
01/05/2021 | 0 | 0
01/06/2021 | 0 | 0
01/07/2021 | 0 | 0
01/08/2021 | 0 | 0
01/09/2021 | 17 | 44
01/10/2021 | 0 | 0
01/11/2021 | 10 | 14
01/12/2021 | 0 | 0
01/01/2022 | 14 | 34
01/02/2022 | 0 | 0
01/03/2022 | 0 | 0
(您可能需要调整 startDate
生成中的月份部分或 Enumerable.Range()
中的起始值,例如包括当前月份,如果这是您更喜欢的.)
示例 fiddle here.