我有以下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;
最主要的是最小,最大和跨度。基本上,“组”中任何与组中其他任何货物在59分钟之内具有DeliverFrom日期时间的托运货物都将在组中退回。
上面的代码本来对我来说看起来不错,但经过进一步检查,似乎该组中有2条以上的记录-2条记录的DeliverFrom日期彼此间隔59分钟,而一条记录的DeliverFrom日期不在59分钟之内,则该查询将不会返回该组,因为它将选择最小值和最大值,并且发现相差超过59分钟。我想发生的事情是,在该组中有2个托运货物,并且DeliverFrom日期足够接近,然后选择一个包含两个托运货物的组。
我将如何去做呢?
编辑:Doh,在此添加了另一个子句。有一个名为“ Weight”的字段,一个名为“ Spaces”的字段,每个组最多可以有26个Weight和26个Spaces
最佳答案
我将使用与您相同的逻辑将货物分组,但是使用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;
}
}
我没有尝试过,但是据我所知它应该可以工作。