property - order by list c# linq
Usando IComparer para clasificar (4)
Estoy tratando de usar un IComparer
para ordenar una lista de puntos. Aquí está la clase de IComparer:
public class CoordinatesBasedComparer : IComparer
{
public int Compare(Object q, Object r)
{
Point a = (p)q;
Point b = (p)r;
if ((a.x == b.x) && (a.y == b.y))
return 0;
if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
return -1;
return 1;
}
}
En el código del cliente, estoy tratando de usar esta clase para ordenar una lista de puntos p (de tipo List<Point>
):
CoordinatesBasedComparer c = new CoordinatesBasedComparer();
Points.Sort(c);
Los errores del código hacia fuera. Aparentemente, se espera que IComparer<Point>
sea un argumento para ordenar el método.
¿Qué necesito hacer para arreglar esto?
Es necesario implementar la interfaz de tipo fuerte ( MSDN ).
public class CoordinatesBasedComparer : IComparer<Point>
{
public int Compare(Point a, Point b)
{
if ((a.x == b.x) && (a.y == b.y))
return 0;
if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
return -1;
return 1;
}
}
Por cierto, creo que usas demasiadas llaves, creo que deberían usarse solo cuando contribuyen al compilador. Esta es mi versión:
if (a.x == b.x && a.y == b.y)
return 0;
if (a.x < b.x || (a.x == b.x && a.y < b.y))
return -1;
Igual que no me gusta la gente que usa return (0)
.
Tenga en cuenta que si apunta a una aplicación .Net-3.5 + puede usar LINQ, que es más fácil e incluso más rápido con la clasificación.
La versión LINQ puede ser algo como:
var orderedList = Points.OrderBy(point => point.x)
.ThenBy(point => point.y)
.ToList();
Si eres lento como yo, el -1 y 1 pueden ser difíciles de razonar al usar IComparer
. La forma de pensarlo es cuando x
debería ir primero, devuelve -1. Cuando y
debe ir primero, devuelve 1.
Todavía puede ser confuso si tiene muchos campos por ordenar. Puede usar un Enum
para hacer que su lógica de comparación sea más legible que 1 y -1, luego emita el resultado.
Este ejemplo coloca los objetos con la menor cantidad de campos nulos en el frente.
public class NullishObjectsToTheBackOfTheLine: IComparer<ClassToCompare>
{
private enum Xy
{
X = -1,
Both = 0,
Y = 1
};
//the IComparer implementation wraps your readable code in an int cast.
public int Compare(ClassToCompare x, ClassToCompare y)
{
return (int) CompareXy(x, y);
}
private static Xy CompareXy(ClassToCompare x, ClassToCompare y)
{
if (x == null && y == null) return Xy.Both;
//put any nulls at the end of the list
if (x == null) return Xy.Y;
if (y == null) return Xy.X;
if (x.Country == y.Country && x.ProductId == y.ProductId) return Xy.Both;
//put the least amount of at the front
if (x.ProductId == null && x.Country == null) return Xy.Y;
if (y.ProductId == null && y.Country == null) return Xy.X;
//put the country values that are not nulls in front
if (x.Country != y.Country) return x.Country != null ? Xy.X : Xy.Y;
//if we got this far, one of these has a null product id and the other doesn''t
return x.ProductId != null ? Xy.X : Xy.Y;
}
}
public class ClassToCompare
{
public string Country { get; set; }
public string ProductId { get; set; }
}
InvalidOperation
un error de InvalidOperation
al agregar un objeto de tipo MyClass
a una lista SortedList<MyClass>
. Estaba, incorrectamente, implementando la interfaz de IComparer. Lo que necesitaba implementar era IComparable con el método CompareTo (MyClass other), en lugar de ICompare.Compare (MyClass x, MyClass y). Este es un ejemplo simplificado:
SortedList<MyClass> sortedList = new SortedList<MyClass>();
MyClass a=new MyClass(), b=new MyClass();
sortedList.Add(a);
sortedList.Add(b); // Note, sort only happens once second element is added
Esto lo arregló :
public class MyClass : IComparable<MyClass>
{
int IComparable<MyClass>.CompareTo(MyClass other)
{
// DoCompareFunction(this, other); and return -1,0,1
}
}
Esto se rompió (no haga esto si agrega a SortedList<MyClass>
) :
public class MyClass : IComparer<MyClass>
{
int IComparable<MyClass>.Compare(MyClass x, MyClass y)
{
// DoCompareFunction(x, y); and return -1,0,1
}
}
Este fue el error:
Error al comparar dos elementos en la matriz.
en System.Collections.Generic.ArraySortHelper`1.BinarySearch (T [] array, índice Int32, longitud Int32, valor T, comparador IComparer`1)
en System.Array.BinarySearch [T] (T [] array, índice Int32, longitud Int32, valor T, comparador IComparer`1)
en System.Collections.Generic.SortedList`2.Add (tecla TKey, valor de TValue)
public class CoordinatesBasedComparer : IComparer, IComparer<Point>
{
public int Compare(Point a, Point b)
{
if ((a.x == b.x) && (a.y == b.y))
return 0;
if ((a.x < b.x) || ((a.x == b.x) && (a.y < b.y)))
return -1;
return 1;
}
int IComparer.Compare(Object q, Object r)
{
return Compare((Point)q, (Point)r);
}
}