linq Group By 并获取 first 和 lats 记录
linq Group By and take first and lats records
我正在处理对我来说可能简单但困难的问题。
我正在为停放的汽车拍照,并通过车牌保存它们并加盖时间戳。同一辆车一天可以拍好几次
示例数据
Plate
Brand
Model
InsertDate
99AA111
Tesla
S
2022-01-17 04:00:00
99AA111
Tesla
S
2022-01-17 04:30:00
99AA111
Tesla
S
2022-01-17 05:00:00
59TA3312
Nissan
Skyline
2022-01-17 04:00:00
59TA3312
Nissan
Skyline
2022-01-17 04:30:00
129EA512
Subaru
Impreza
2022-01-17 03:30:00
我想要实现的是;
Plate
Brand
Model
FirstPhotoDate
SecondPhotoDate
99AA111
Tesla
S
2022-01-17 04:00:00
2022-01-17 04:30:00
99AA111
Tesla
S
2022-01-17 05:00:00
-
59TA3312
Nissan
Skyline
2022-01-17 04:00:00
2022-01-17 04:30:00
129EA512
Subaru
Impreza
2022-01-17 03:30:00
-
我想到了;
var groupedResult = resultList.GroupBy(f => f.Plate).Select(f => new ResultListView
{
Plate = f.Key,
FirstDate = f.Min(f => f.InsertDate),
SecondDate = f.Max(f => f.InsertDate),
Brand = f.FirstOrDefault().Brand,
Model = f.FirstOrDefault().Model,
TimeDifference = (f.Max(f => f.InsertDate) - f.Min(f => f.InsertDate)).TotalMinutes
});
但是在代码中很明显,它只给了我第一条和最后一条记录,而不是我预期的那样。我正在尝试按盘子分组,如果同一个盘子不止一次,请将其与下一个盘子匹配。如果只有一张照片或三张照片,则第二个日期应为空。
当然可以应用不同的逻辑,但我相信这是更清晰的方法。
我认为在分组结果中循环。取第一个和第二个并跳过两个。但这不是我要找的。
感谢您的帮助。
嗯,有(让我们使用命名元组来演示):
var resultList = new (string Plate, string Brand, string Model, DateTime InsertDate)[] {
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,00,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,30,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 05,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,30,00)),
("129EA512", "Subaru", "Impreza", new DateTime(2022,01,17, 03,30,00)),
};
你可以GroupBy
两次:
var groupedResult = resultList
.GroupBy(item => item.Plate)
.SelectMany(group => group
.OrderBy(item => item.InsertDate)
.Select((item, index) => (item: item, index: index / 2))
.GroupBy(pair => pair.index)
.Select(g => (
Plate: g.First().item.Plate,
Brand: g.First().item.Brand,
Model: g.First().item.Model,
FirstPhotoDate: g.First().item.InsertDate,
SecondPhotoDate: (g.Count() == 1 ? null : (DateTime?)(g.Last().item.InsertDate))
))
);
一起来看看:
string report = string.Join(Environment.NewLine, groupedResult
.Select(r => $"{r.Plate,-8} : {r.Brand,-6} : {r.Model,-7} : {r.FirstPhotoDate} : {r.SecondPhotoDate}"));
Console.Write(report);
结果:
99AA111 : Tesla : S : 17.01.2022 4:00:00 : 17.01.2022 4:30:00
99AA111 : Tesla : S : 17.01.2022 5:00:00 :
59TA3312 : Nissan : Skyline : 17.01.2022 4:00:00 : 17.01.2022 4:30:00
129EA512 : Subaru : Impreza : 17.01.2022 3:30:00 :
这是我能想到的最干净的方法:
var resultList = new (string Plate, string Brand, string Model, DateTime InsertDate)[]
{
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,00,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,30,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 05,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,30,00)),
("129EA512", "Subaru", "Impreza", new DateTime(2022,01,17, 03,30,00)),
};
var query =
from r in resultList
group (DateTime?)r.InsertDate by new { r.Plate, r.Brand, r.Model } into grs
from bgrs in grs.OrderBy(x => x).Buffer(2)
select new
{
grs.Key.Plate,
grs.Key.Brand,
grs.Key.Model,
FirstPhotoDate = bgrs.First(),
SecondPhotoDate = bgrs.Skip(1).Any() ? bgrs.Last() : null,
};
我使用了 Microsoft System.Interactive
NuGet 中的 Buffer
运算符。
这给了我:
我正在处理对我来说可能简单但困难的问题。 我正在为停放的汽车拍照,并通过车牌保存它们并加盖时间戳。同一辆车一天可以拍好几次
示例数据
Plate | Brand | Model | InsertDate |
---|---|---|---|
99AA111 | Tesla | S | 2022-01-17 04:00:00 |
99AA111 | Tesla | S | 2022-01-17 04:30:00 |
99AA111 | Tesla | S | 2022-01-17 05:00:00 |
59TA3312 | Nissan | Skyline | 2022-01-17 04:00:00 |
59TA3312 | Nissan | Skyline | 2022-01-17 04:30:00 |
129EA512 | Subaru | Impreza | 2022-01-17 03:30:00 |
我想要实现的是;
Plate | Brand | Model | FirstPhotoDate | SecondPhotoDate |
---|---|---|---|---|
99AA111 | Tesla | S | 2022-01-17 04:00:00 | 2022-01-17 04:30:00 |
99AA111 | Tesla | S | 2022-01-17 05:00:00 | - |
59TA3312 | Nissan | Skyline | 2022-01-17 04:00:00 | 2022-01-17 04:30:00 |
129EA512 | Subaru | Impreza | 2022-01-17 03:30:00 | - |
我想到了;
var groupedResult = resultList.GroupBy(f => f.Plate).Select(f => new ResultListView
{
Plate = f.Key,
FirstDate = f.Min(f => f.InsertDate),
SecondDate = f.Max(f => f.InsertDate),
Brand = f.FirstOrDefault().Brand,
Model = f.FirstOrDefault().Model,
TimeDifference = (f.Max(f => f.InsertDate) - f.Min(f => f.InsertDate)).TotalMinutes
});
但是在代码中很明显,它只给了我第一条和最后一条记录,而不是我预期的那样。我正在尝试按盘子分组,如果同一个盘子不止一次,请将其与下一个盘子匹配。如果只有一张照片或三张照片,则第二个日期应为空。
当然可以应用不同的逻辑,但我相信这是更清晰的方法。
我认为在分组结果中循环。取第一个和第二个并跳过两个。但这不是我要找的。
感谢您的帮助。
嗯,有(让我们使用命名元组来演示):
var resultList = new (string Plate, string Brand, string Model, DateTime InsertDate)[] {
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,00,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,30,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 05,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,30,00)),
("129EA512", "Subaru", "Impreza", new DateTime(2022,01,17, 03,30,00)),
};
你可以GroupBy
两次:
var groupedResult = resultList
.GroupBy(item => item.Plate)
.SelectMany(group => group
.OrderBy(item => item.InsertDate)
.Select((item, index) => (item: item, index: index / 2))
.GroupBy(pair => pair.index)
.Select(g => (
Plate: g.First().item.Plate,
Brand: g.First().item.Brand,
Model: g.First().item.Model,
FirstPhotoDate: g.First().item.InsertDate,
SecondPhotoDate: (g.Count() == 1 ? null : (DateTime?)(g.Last().item.InsertDate))
))
);
一起来看看:
string report = string.Join(Environment.NewLine, groupedResult
.Select(r => $"{r.Plate,-8} : {r.Brand,-6} : {r.Model,-7} : {r.FirstPhotoDate} : {r.SecondPhotoDate}"));
Console.Write(report);
结果:
99AA111 : Tesla : S : 17.01.2022 4:00:00 : 17.01.2022 4:30:00
99AA111 : Tesla : S : 17.01.2022 5:00:00 :
59TA3312 : Nissan : Skyline : 17.01.2022 4:00:00 : 17.01.2022 4:30:00
129EA512 : Subaru : Impreza : 17.01.2022 3:30:00 :
这是我能想到的最干净的方法:
var resultList = new (string Plate, string Brand, string Model, DateTime InsertDate)[]
{
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,00,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 04,30,00)),
("99AA111", "Tesla", "S", new DateTime(2022,01,17, 05,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,00,00)),
("59TA3312", "Nissan", "Skyline", new DateTime(2022,01,17, 04,30,00)),
("129EA512", "Subaru", "Impreza", new DateTime(2022,01,17, 03,30,00)),
};
var query =
from r in resultList
group (DateTime?)r.InsertDate by new { r.Plate, r.Brand, r.Model } into grs
from bgrs in grs.OrderBy(x => x).Buffer(2)
select new
{
grs.Key.Plate,
grs.Key.Brand,
grs.Key.Model,
FirstPhotoDate = bgrs.First(),
SecondPhotoDate = bgrs.Skip(1).Any() ? bgrs.Last() : null,
};
我使用了 Microsoft System.Interactive
NuGet 中的 Buffer
运算符。
这给了我: