2010-02-17 20 views
11

tengo esta clasecómo agrupar por tipos personalizados con LINQ

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

Con Coordinar se definen así:

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

Y yo quiero tener una consulta LINQ así:

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

As mentioned here by MSDN Pensé que esto era posible si anulara Equals en mi clase de coordenadas:

Use un tipo con nombre si debe pasar la variable de consulta a otro método. Cree una clase especial utilizando propiedades implementadas automáticamente para las claves , y luego anule los métodos Igual y GetHashCode. También puede usar una estructura, en cuyo caso usted no debe estrictamente tener que anular esos métodos . Para obtener más información, consulte Cómo : Implementar una clase inmutable que posee propiedades implementadas-Auto

Igual aplicación para Coordinar la clase:

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

todavía no puedo conseguir mi consulta LINQ para agrupar por coordenadas similares , ya que mi no prueba muestra:

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

Hay una sobrecarga de el método GrouBy que toma un IEqualityComparer como parámetro, pero ¿existe el equivalente usando la cláusula group? ¿Estoy haciendo algo mal? ¿Alguna idea?

Respuesta

22

Has demostrado la implementación Equals, pero no GetHashCode. Debe anular ambos (y de forma consistente) para que la agrupación funcione.

Muestra aplicación GetHashCode:

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

Tenga en cuenta que la comparación de los valores de la igualdad float exacta es siempre un poco arriesgado - pero al menos esperaría que las pruebas unitarias para pasar, dado que no está realizando ningún cálculo .

+0

Sólo probado, eso es lo que Estaba faltando.Gracias :) :) anulación pública int GetHashCode() { return ((int) Latitude * 100)^((int) Longitude * 100); } –

+0

Si eso es lo que hace su código hash, debe asegurarse de que su código de igualdad coincida con él, deben ser coherentes entre sí. –

+0

Latitude.GetHashCode()^Longitude.GetHashCode() da los mismos resultados cuando se invierte Latitud y Longitud. Entonces esa no fue una buena solución, ya que quiero asegurar que coord (x, y)! = Coord (y, x); Su código funciona ya que importa el orden de las operaciones. Gracias por la precisión, eso ayudó :) –

2

hay una sobrecarga a la método GrouBy que toma un IEqualityComparer como un parámetro, pero es allí la equivalente utilizando la cláusula grupo?

Siempre se puede agrupar por un tipo anónimo, si lo que desea es una solución en línea rápido y no está preocupado por golpear el tipo exacto de las teclas:

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

Conocía esa solución, pero no tendrá la clase de coordenadas como clave, solo un tipo anónimo. –