在LINQ中查找类似的记录

时间:2012-01-13 15:12:37

标签: c# linq grouping

我有以下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个空格

2 个答案:

答案 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;
    }
}

我没试过这个,但据我所知它应该有用。