我有以下LINQ查询,该查询将用于查找类似的任何货物':
from c in cons
group c by new { c.TripDate.Value, c.DeliveryPostcode, c.DeliveryName } into cg
let min = cg.Min(a => a.DeliverFrom)
let max = cg.Max(a => a.DeliverFrom)
let span = max - min
where span.TotalMinutes <= 59
select cg;
主要是min,max和span。基本上,在组中任何其他人的59分钟内具有DeliverFrom日期时间的&#39;组中的任何货物将在组中返回。
上面的代码原本对我来说看起来不错,但经过进一步检查,如果该组中有超过2条记录 - 其中2条DeliverFrom日期为59分钟,而其中一条日期为DeliverFrom < em> not 在任何59分钟内,然后查询将不会返回该组,因为它将选择min和max并且看到差异超过59分钟。我想要发生的是看到组中有2个托运,DeliverFrom日期足够接近,只需选择一个包含它们的组。
我该怎么做呢?
编辑:Doh,其中添加了另一个条款。这里有一个名为“重量”的字段。还有一个名为“Spaces&#39;”的组,每组最多可以有26个重量和26个空格答案 0 :(得分:3)
如果我没有弄错的话,你所寻找的是一个名为cluster identification的统计问题,如果是这样的话,这是一个比你想象的要复杂得多的问题。
作为思考练习,想象一下,如果您有3个参赛作品,分别是1:00,1:30和2:00。你想怎么把这些分组?前两个或后两个可以作为一个组(相隔不到59分钟),但所有3个都不会。
如果您只想将项目链接到一个组中,只要它们在组中任何其他项目的59分钟内,您就需要继续迭代,直到您停止查找要添加到任何群集的新项目。
答案 1 :(得分:1)
我会像您一样使用相同的逻辑对货物进行分组,但使用GroupBy
代替this overload,允许我将每组货物投影到另一种类型。这种类型在这里是一系列可用的一系列货物,每个元素代表不仅在同一组中开始的货物,而且还应该在一小时的持续时间内交付。因此resultSelector
的签名将是
Func<anontype, IEnumerable<Consignment>, IEnumerable<IEnumerable<Consignment>>>
此时很明显,为分组定义类型可能是个好主意,这样你就可以摆脱上述签名中的匿名类型;否则你将被迫将resultSelector
定义为lambda。
在resultSelector
内,您首先需要按DeliverFrom
对传入的托运组进行排序,然后根据该时间返回子组。所以它可能看起来像这样:
IEnumerable<IEnumerable<Consignment>>
Partitioner(ConsignmentGroupKey key, IEnumerable<Consignment> cg)
{
cg = cg.OrderBy(c => c.DeliverFrom);
var startTime = cg.First().DeliverFrom;
var subgroup = new List<Consignment>();
foreach(var cons in cg) {
if ((cons.DeliverFrom - startTime).TotalMinutes < 60) {
subgroup.Add(cons);
}
else {
yield return subgroup;
startTime = cons.DeliverFrom;
subgroup = new List<Consignment>() { cons };
}
}
if (subgroup.Count > 0) {
yield return subgroup;
}
}
我没试过这个,但据我所知它应该有用。