2010-02-17 3 views
11

Tôi có lớp nàyLàm thế nào để nhóm theo loại tùy chỉnh với LINQ

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

Với Phối hợp được xác định như thế này:

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

Và tôi muốn có một truy vấn LINQ như thế:

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

As mentioned here by MSDN Tôi nghĩ rằng điều này là có thể nếu tôi ghi đè lên Bằng trên lớp Tọa độ của mình:

Sử dụng loại được đặt tên nếu bạn phải chuyển biến số truy vấn sang phương thức khác. Tạo một lớp đặc biệt bằng cách sử dụng thuộc tính được tự động triển khai cho các phím và sau đó ghi đè phương thức Equals và GetHashCode. Bạn cũng có thể sử dụng cấu trúc , trong trường hợp đó bạn không nghiêm chỉnh phải ghi đè các phương thức đó. Để biết thêm thông tin xem thế nào để: Thực hiện một lớp Immutable Đó Có Thuộc tính Auto-thực hiện

Equals thực hiện cho Tọa độ lớp:

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

tôi vẫn không thể nhận được truy vấn LINQ của tôi vào nhóm theo tọa độ tương tự , như tôi không thử nghiệm cho thấy:

[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()); 
} 

có một tình trạng quá tải để phương thức GrouBy lấy IEqualityComparer làm tham số, nhưng có tương đương với mệnh đề nhóm không? Tôi có làm gì sai không ?? Có suy nghĩ gì không?

Trả lời

22

Bạn đã hiển thị việc thực hiện Bằng, nhưng không hiển thị GetHashCode. Bạn cần ghi đè cả hai (và theo cách nhất quán) để nhóm hoạt động.

mẫu thực hiện GetHashCode:

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

Lưu ý rằng so sánh float giá trị cho sự bình đẳng chính xác luôn là hơi mạo hiểm - nhưng tôi ít nhất là mong muốn kiểm tra đơn vị của bạn để vượt qua, cho rằng họ không thực hiện bất kỳ tính toán .

+0

Chỉ cần thử nó, đó là những gì tôi đã mất tích.Tuyệt vời Cảm ơn bạn :) ghi đè công khai int GetHashCode() { return ((int) Latitude * 100)^((int) Longitude * 100); } –

+0

Nếu đó là những gì mã băm của bạn đang làm, bạn nên đảm bảo rằng mã bình đẳng của bạn khớp với nó - chúng phải nhất quán với nhau. –

+0

Latitude.GetHashCode()^Longitude.GetHashCode() cho kết quả tương tự khi đảo ngược vĩ độ và kinh độ. Vì vậy, đó không phải là một giải pháp tốt vì tôi muốn đảm bảo rằng điều phối (x, y)! = Coord (y, x); Mã của bạn hoạt động theo thứ tự các hoạt động quan trọng. Cảm ơn sự chính xác, đã giúp :) –

2

Có một tình trạng quá tải cho GrouBy phương pháp mà phải mất một IEqualityComparer như một tham số, nhưng là có các tương đương sử dụng mệnh đề nhóm?

Bạn luôn có thể nhóm bởi một loại vô danh, nếu bạn chỉ muốn một giải pháp nội tuyến nhanh chóng và không lo lắng về việc đánh loại chính xác cho các phím:

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

Tôi biết rằng giải pháp, nhưng bạn sẽ không có lớp phối hợp làm khóa, chỉ là một loại ẩn danh. –