如何使用IEnumerable.GroupBy通过比较元素之间的多个属性?

xb4*_*7m5 6 c# linq

如何将“相邻”网站分组:

给定数据:

List<Site> sites = new List<Site> {
    new Site { RouteId="A", StartMilepost=0.00m, EndMilepost=1.00m },
    new Site { RouteId="A", StartMilepost=1.00m, EndMilepost=2.00m },
    new Site { RouteId="A", StartMilepost=5.00m, EndMilepost=7.00m },
    new Site { RouteId="B", StartMilepost=3.00m, EndMilepost=5.00m },
    new Site { RouteId="B", StartMilepost=11.00m, EndMilepost=13.00m },
    new Site { RouteId="B", StartMilepost=13.00m, EndMilepost=14.00m },
};
Run Code Online (Sandbox Code Playgroud)

我想要结果:

[
    [
        Site { RouteId="A", StartMilepost=0.00m, EndMilepost=1.00m },
        Site { RouteId="A", StartMilepost=1.00m, EndMilepost=2.00m }
    ],
    [
        Site { RouteId="A", StartMilepost=5.00m, EndMilepost=7.00m }
    ],
    [
        Site { RouteId="B", StartMilepost=3.00m, EndMilepost=5.00m }
    ],
    [
        Site { RouteId="B", StartMilepost=11.00m, EndMilepost=13.00m },
        Site { RouteId="B", StartMilepost=13.00m, EndMilepost=14.00m }
    ]
]
Run Code Online (Sandbox Code Playgroud)

我尝试使用具有自定义比较器功能的GroupBy来检查routeIds匹配,并且第一个站点的终点里程等于下一个站点的起点里程。我的HashKey函数只是签出routeId,因此路由中的所有站点都将被合并在一起,但我认为比较器会做出一个假设,例如,如果A = B,并且B = C,那么A = C,因此C不会与A分组,B,C,因为在我的邻接案例中,A将不等于C。

Sin*_*atr 1

我很惊讶它GroupBy没有超载Func<..., bool>就地分组而无需实现自定义类的麻烦。

所以我创建了一个:

public static IEnumerable<IEnumerable<T>> GroupBy<T>(this IEnumerable<T> source, Func<T, T, bool> func)
{
    var items = new List<T>();
    foreach (var item in source)
    {
        if (items.Count != 0)
            if (!func(items[0], item))
            {
                yield return items;
                items = new List<T>();
            }
        items.Add(item);
    }
    if (items.Count != 0)
        yield return items;
}
Run Code Online (Sandbox Code Playgroud)

用法:

var result = sites.GroupBy((x, y) => x.RouteId == y.RouteId &&
    x.StartMilepost <= y.EndMilepost && x.EndMilepost >= y.StartMilepost).ToList();
Run Code Online (Sandbox Code Playgroud)

这应该会产生想要的结果。

关于实施的几句话。在上面的扩展方法中,您必须提供委托,如果xy应该分组,该委托应该返回 true。该方法很愚蠢,只会按照相邻项目出现的顺序进行比较。您的输入是有序的,但您可能必须在将其与其他内容一起使用之前使用OrderBy/ 。ThenBy