代码之家  ›  专栏  ›  技术社区  ›  Stéphane

如何使用linq按自定义类型分组

  •  11
  • Stéphane  · 技术社区  · 16 年前

    我有这门课

    public class Item
    {
           public Coordinate coordinate { get; set; }
            ...
            ...
    }
    

    坐标的定义如下:

    public class Coordinate
    {
            public Coordinate(float latitude, float longitude)
            {
                Latitude = latitude;
                Longitude = longitude;
            }
    
            public float Latitude { get; private set; }
            public float Longitude { get; private set; }
    }
    

    我想要一个像这样的linq查询:

    var grouped = from it in items
                  group it by it.Coordinate into grp
                  select grp;
    

    As mentioned here by MSDN

    如果必须通过 查询变量到另一个方法。 使用创建一个特殊类 自动实现的属性 和GetHashCode方法。你也可以 使用struct,在这种情况下,您不需要 我们必须严格遵守这些规定 方法。有关更多信息,请参见如何 to:实现一个不可变的类 具有自动实现的属性

    public override bool Equals(object obj)
    {
           var coord = obj as Coordinate;
           if(coord == null) return false;
           return (Latitude == coord.Latitude && Longitude == coord.Longitude);
    }
    

    尽管如此,我还是无法将linq查询按类似的坐标分组,因为我的 弱点 测试结果显示:

    [TestMethod]
    public void GroupBy_3ItemsWith2DifferentCoordinates_Returns2Groups()
    {
        var items = new List<Item>
            {
                new Item {Coordinate = new Coordinate(10, 10)},
                new Item {Coordinate = new Coordinate(10, 10)},
                new Item {Coordinate = new Coordinate(12, 10)},
            };
        var grouped = from it in items
                      group it by it.Coordinate into g
                      select g;
        Assert.AreEqual(2, grouped.Count());
    }
    

    Groupby方法有一个重载,该重载将IEqualityComparer作为参数,但是否有使用group子句的等价项? 我做错什么了吗??有什么想法吗?

    2 回复  |  直到 16 年前
        1
  •  24
  •   mellamokb Dan    15 年前

    您已经展示了Equals实现,但没有展示GetHashCode。为了使分组工作,您需要同时覆盖这两个选项(并且以一致的方式)。

    public override int GetHashCode()
    {
        int hash = 23;
        hash = hash * 31 + Latitude.GetHashCode();
        hash = hash * 31 + Longitude.GetHashCode();
        return hash;
    }
    

    注意,比较 float 精确相等的值总是有点冒险——但我至少希望您的单元测试能够通过,因为它们没有执行任何计算。

        2
  •  2
  •   Amy B    16 年前

    格劳比号超载了 方法,该方法接受IEqualityComparer 作为参数,但是否存在 使用group子句是否等效?

    如果您只需要一个快速的内联解决方案,并且不担心键入键的确切类型,则始终可以按匿名类型分组:

    var grouped =
      from it in items 
      group it by new {it.Coordinate.Latitude, it.Coordinate.Longitude};