Tengo una clase siguiente:
[DataContract]
public class Pair<TKey, TValue> : INotifyPropertyChanged, IDisposable
{
public Pair(TKey key, TValue value)
{
Key = key;
Value = value;
}
#region Properties
[DataMember]
public TKey Key
{
get
{ return m_key; }
set
{
m_key = value;
OnPropertyChanged("Key");
}
}
[DataMember]
public TValue Value
{
get { return m_value; }
set
{
m_value = value;
OnPropertyChanged("Value");
}
}
#endregion
#region Fields
private TKey m_key;
private TValue m_value;
#endregion
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
#endregion
#region IDisposable Members
public void Dispose()
{ }
#endregion
}
Que he puesto en un ObservableCollection:
ObservableCollection<Pair<ushort, string>> my_collection =
new ObservableCollection<Pair<ushort, string>>();
my_collection.Add(new Pair(7, "aaa"));
my_collection.Add(new Pair(3, "xey"));
my_collection.Add(new Pair(6, "fty"));
P: ¿Cómo lo clasifico por clave?
Respuestas:
Se puede ordenar un observable y devolver el mismo objeto ordenado mediante un método de extensión. Para colecciones más grandes, tenga cuidado con la cantidad de notificaciones de cambios de colección.
He actualizado mi código para mejorar el rendimiento y manejar duplicados (gracias a nawfal por resaltar el bajo rendimiento del original a pesar de que funcionó bien en el ejemplo de datos original). El observable se divide en una mitad ordenada a la izquierda y una mitad derecha sin clasificar, donde cada vez que el elemento mínimo (como se encuentra en la lista ordenada) se desplaza al final de la partición ordenada desde la no ordenada. Peor caso O (n). Esencialmente una ordenación por selección (consulte la salida a continuación).
uso: muestra con un observador (usó una clase Person para que sea simple)
Detalles del progreso de clasificación que muestran cómo se pivota la colección:
La clase Person implementa IComparable e IEquatable, este último se usa para minimizar los cambios en la colección a fin de reducir la cantidad de notificaciones de cambios generadas
Para devolver un ObservableCollection, llame a .ToObservableCollection en * sortedOC * usando, por ejemplo, [esta implementación] [1].
**** respuesta orig: esto crea una nueva colección **** Puede usar linq como lo ilustra el método doSort a continuación. Un fragmento de código rápido: produce
3: xey 6: fty 7: aaa
Alternativamente, puede usar un método de extensión en la propia colección
fuente
ObservableCollection
, sino que crea una nueva colección.BinarySearch
lugar deIndexOf
.Esta simple extensión funcionó muy bien para mí. Solo tenía que asegurarme de que así
MyObject
fueraIComparable
. Cuando se llama al método sort en la colección observable deMyObjects
, se llama alCompareTo
método onMyObject
, que llama a mi método Logical Sort. Si bien no tiene todas las campanas y silbidos del resto de las respuestas publicadas aquí, es exactamente lo que necesitaba.fuente
return Utils.LogicalStringCompare(a.Title, b.Title);
lugar dereturn string.Compare(a.Title, b.Title);
? @NeilWEncontré una entrada de blog relevante que proporciona una mejor respuesta que las de aquí:
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
ACTUALIZAR
La ObservableSortedList que @romkyns señala en los comentarios mantiene automáticamente el orden de clasificación.
Sin embargo, tenga en cuenta también la observación
fuente
Puede utilizar este sencillo método:
Puedes ordenar así:
Más detalles: http://jaider.net/2011-05-04/sort-a-observablecollection/
fuente
ObservableCollection
vinculado a ItemSource de los menús desplegables y no ve la colección en absoluto. Además, esta operación de limpieza y llenado es ultra rápida ... la "lenta" puede ser del tipo que ya está optimizado. finalmente, puede modificar este código para implementar su método de movimiento, tener elsortedlist
ysource
el resto es fácil.Move
eventos, eso también solo para los realmente movidos.WPF proporciona clasificación en vivo lista para usar usando la
ListCollectionView
clase ...Una vez que se completa esta inicialización, no hay nada más que hacer. La ventaja sobre una ordenación pasiva es que ListCollectionView hace todo el trabajo pesado de una manera que es transparente para el desarrollador. Los elementos nuevos se colocan automáticamente en su orden de clasificación correcto. Cualquier clase que se derive
IComparer
de T es adecuada para la propiedad de ordenación personalizada.Consulte ListCollectionView para obtener la documentación y otras características.
fuente
Me gustó el enfoque del método de extensión de clasificación de burbujas en el blog de "Richie" anterior, pero no necesariamente quiero clasificar comparando todo el objeto. Más a menudo quiero ordenar por una propiedad específica del objeto. Así que lo modifiqué para aceptar un selector de clave de la forma en que lo hace OrderBy para que pueda elegir en qué propiedad ordenar:
Que llamaría de la misma manera que llamaría OrderBy, excepto que ordenará la instancia existente de su ObservableCollection en lugar de devolver una nueva colección:
fuente
OrderBy
y luego hacer una comparación para descubrir el cambio real.La respuesta de @ NielW es el camino a seguir, para una clasificación real en el lugar. Quería agregar una solución ligeramente alterada que le permita evitar tener que usar
IComparable
:ahora puede llamarlo como la mayoría de los métodos LINQ:
fuente
if(!Ascending) sorted.Reverse();
justo antes defor
: D (y no hay necesidad de preocuparse más por la memoria, ese método Reverse no crea ningún objeto nuevo, está en el lugar inverso)Me gustaría agregar a la respuesta de NeilW . Incorporar un método que se asemeje al orderby. Agregue este método como una extensión:
Y usa como:
fuente
Una variación es donde clasifica la colección en su lugar usando un algoritmo de clasificación de selección . Los elementos se mueven a su lugar utilizando el
Move
método. Cada movimiento disparará elCollectionChanged
evento conNotifyCollectionChangedAction.Move
(y tambiénPropertyChanged
con el nombre de la propiedadItem[]
).Este algoritmo tiene algunas propiedades interesantes:
CollectionChanged
eventos activados) es casi siempre menor que otros algoritmos similares como el ordenamiento por inserción y el ordenamiento por burbujas.El algoritmo es bastante simple. La colección se itera para encontrar el elemento más pequeño que luego se mueve al inicio de la colección. El proceso se repite comenzando en el segundo elemento y así sucesivamente hasta que todos los elementos se hayan colocado en su lugar. El algoritmo no es muy eficiente, pero para cualquier cosa que vaya a mostrar en una interfaz de usuario, no debería importar. Sin embargo, en términos de número de operaciones de movimiento, es bastante eficiente.
Aquí hay un método de extensión que por simplicidad requiere que los elementos implementen
IComparable<T>
. Otras opciones están usando unIComparer<T>
o unFunc<T, T, Int32>
.Ordenar una colección es simplemente una cuestión de invocar el método de extensión:
fuente
T
ser capaz de ordenar los elementos de la colección. La ordenación implica el concepto de mayor y menor que y solo usted puede definir cómoProfileObject
se ordena. Para usar el método de extensión, debe implementarIComparable<ProfileObject>
enProfileObject
. Otras alternativas son como se indica especificando unIComparer<ProfileObject>
o unFunc<ProfileObject, ProfileObject, int>
y cambiar el código de clasificación en consecuencia.Para mejorar un poco el método de extensión en la respuesta xr280xr, agregué un parámetro bool opcional para determinar si la clasificación es descendente o no. También incluí la sugerencia de Carlos P en el comentario a esa respuesta. Por favor ver más abajo.
fuente
¿Necesitas mantener tu colección ordenada en todo momento? Al recuperar los pares, ¿necesita que estén siempre ordenados o solo unas pocas veces (tal vez solo para presentar)? ¿Qué tan grande espera que sea su colección? Hay muchos factores que pueden ayudarlo a decidir qué método utilizar.
Si necesita que la colección esté ordenada en todo momento, incluso cuando inserta o elimina elementos y la velocidad de inserción no es un problema, tal vez debería implementar algún tipo de lo
SortedObservableCollection
que mencionó @Gerrie Schenck o ver esta implementación .Si necesita ordenar su colección solo unas pocas veces, use:
Esto llevará algún tiempo ordenar la colección, pero aun así, podría ser la mejor solución dependiendo de lo que esté haciendo con ella.
fuente
Mi respuesta actual ya tiene la mayor cantidad de votos, pero encontré una forma mejor y más moderna de hacer esto.
fuente
Cree una nueva clase
SortedObservableCollection
, derívelaObservableCollection
e impleméntelaIComparable<Pair<ushort, string>>
.fuente
Una forma sería convertirlo en una Lista y luego llamar a Sort (), proporcionando un delegado de comparación. Algo como:-
(no probado)
fuente
Creo que esta es la solución más elegante:
http://www.xamlplayground.org/post/2009/07/18/Use-CollectionViewSource-effectively-in-MVVM-applications.aspx
fuente
Qué diablos, también arrojaré una respuesta improvisada rápidamente ... se parece un poco a algunas otras implementaciones aquí, pero la agregaré en cualquier persona:
(apenas probado, ojalá no me esté avergonzando)
Primero establezcamos algunos objetivos (mis suposiciones):
1) Debe ordenar
ObservableCollection<T>
en su lugar, para mantener notificaciones, etc.2) No debe ser terriblemente ineficiente (es decir, algo cercano a la eficiencia de clasificación "buena" estándar)
fuente
Ninguna de estas respuestas funcionó en mi caso. Ya sea porque arruina la encuadernación o requiere tanta codificación adicional que es una especie de pesadilla, o la respuesta simplemente está rota. Entonces, aquí hay otra respuesta más simple que pensé. Es mucho menos código y sigue siendo la misma colección observable con un tipo de método this.sort adicional. Avíseme si hay alguna razón por la que no debería hacerlo de esta manera (eficiencia, etc.).
... Donde ScoutItem es mi clase pública. Parecía mucho más simple. Beneficio agregado: realmente funciona y no se mete con las encuadernaciones ni devuelve una nueva colección, etc.
fuente
Muy bien, dado que tenía problemas para que ObservableSortedList funcionara con XAML, seguí adelante y creé SortingObservableCollection . Hereda de ObservableCollection, por lo que funciona con XAML y lo he probado con una cobertura de código del 98%. Lo he usado en mis propias aplicaciones, pero no prometo que esté libre de errores. Siéntete libre de contribuir. Aquí está el uso de código de muestra:
Es un PCL, por lo que debería funcionar con Windows Store, Windows Phone y .NET 4.5.1.
fuente
new
en todos esos métodos, si alguien tiene una instancia de tipo más genérico, esos métodos no serán llamados. En su lugar,override
cada método reemplazable y cámbielos según sea necesario o recurrabase.Method(...)
. Usted, por ejemplo, ni siquiera necesita preocuparse.Add
porque eso se usa internamente.InsertItem
, por lo que si.InsertItem
se anula y ajusta,.Add
no interferirá con el pedido.Esto es lo que hago con las extensiones OC:
fuente
Esto funcionó para mí, lo encontré hace mucho tiempo en alguna parte.
Uso:
fuente
Necesitaba poder ordenar por varias cosas, no solo por una. Esta respuesta se basa en algunas de las otras respuestas, pero permite una clasificación más compleja.
Cuando lo use, pase una serie de llamadas OrderBy / ThenBy. Me gusta esto:
fuente
Aprendí mucho de las otras soluciones, pero encontré un par de problemas. Primero, algunos dependen de IndexOf, que tiende a ser bastante lento para listas grandes. En segundo lugar, mi ObservableCollection tenía entidades EF y el uso de Eliminar parecía corromper algunas de las propiedades de la clave externa. Quizás estoy haciendo algo mal.
Independientemente, se puede usar A Move en su lugar Eliminar / Insertar, pero eso causa algunos problemas con la corrección de rendimiento.
Para solucionar el problema de rendimiento, creo un diccionario con los valores ordenados IndexOf. Para mantener el diccionario actualizado y preservar las propiedades de la entidad, use un intercambio implementado con dos movimientos en lugar de uno como se implementa en otras soluciones.
Un solo movimiento cambia los índices de los elementos entre las ubicaciones, lo que invalidaría el diccionario IndexOf. Agregar un segundo movimiento para implementar un intercambio restaura las ubicaciones.
fuente
fuente