在LINQ中查找类似记录

本文关键字:记录 查找 LINQ | 更新日期: 2023-09-27 18:20:25

我有以下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;

最重要的是最小值、最大值和跨度。基本上,"组"中的任何发货,如果DeliverFrom日期时间在组中任何其他发货的59分钟内,都将在组中退货。

在我看来,上面的代码最初看起来不错,但经过进一步检查,如果组中有两条以上的记录——两条的DeliverFrom日期相差59分钟,而一条的DeliverStart日期在59分钟内不,那么查询将不会返回该组,因为它将选择最小值和最大值,并看到差异超过59分钟。我想看到的是,在DeliverFrom日期足够近的组中有两个发货,只需选择一个包含这两个发货的组。

我该怎么做?

编辑:Doh,这里面又增加了一个条款。有一个名为"权重"answers"空间"的字段,每组最多可以有26个权重和26个空间

在LINQ中查找类似记录

如果我没有错的话,您正在寻找的是一个称为集群标识的统计问题,如果是这样的话,这是一个比您想象的要复杂得多的问题。

作为一个思维练习,想象一下你有三个条目,分别是1点、1点30分和2点。你想如何将这些分组?前两个或后两个将作为一个小组工作(间隔不到59分钟),但所有三个都不会。

如果您只想将项目链接到一个组中,只要它们与组中的任何其他项目在59分钟内,您就需要不断迭代,直到您停止找到要添加到任何集群中的新项目。

我会像您一样用相同的逻辑对发货进行分组,但使用GroupBy的重载,使我能够将每组组成部分投影到另一种类型中。这种类型在这里是一个可枚举的组成部分组序列,其中的每个元素都表示发货,这些发货不仅一开始就在同一组中,而且应该在一个小时内全部交付。因此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;
    }
}

我还没有尝试过,但据我所知,它应该有效。