2010-10-15 23 views
68

Tengo 2 objetos de lista, uno es solo una lista de ints, el otro es una lista de objetos pero el objeto tiene una propiedad de ID.Ordenar una lista por otra

Lo que quiero hacer es ordenar la lista de objetos por su ID en el mismo orden de clasificación que la lista de entradas.

he estado jugando desde hace un tiempo tratando de conseguir que funcione, hasta el momento no hay alegría,

Esto es lo que tengo hasta ahora ...

//************************** 
//*** Randomize the list *** 
//************************** 
if (Session["SearchResultsOrder"] != null) 
{ 
    // save the session as a int list 
    List<int> IDList = new List<int>((List<int>)Session["SearchResultsOrder"]); 
    // the saved list session exists, make sure the list is orded by this 
    foreach(var i in IDList) 
    { 
     SearchData.ReturnedSearchedMembers.OrderBy(x => x.ID == i); 
    } 
} 
else 
{ 
    // before any sorts randomize the results - this mixes it up a bit as before it would order the results by member registration date       
    List<Member> RandomList = new List<Member>(SearchData.ReturnedSearchedMembers); 
    SearchData.ReturnedSearchedMembers = GloballyAvailableMethods.RandomizeGenericList<Member>(RandomList, RandomList.Count).ToList(); 

    // save the order of these results so they can be restored back during postback 
    List<int> SearchResultsOrder = new List<int>(); 
    SearchData.ReturnedSearchedMembers.ForEach(x => SearchResultsOrder.Add(x.ID)); 
    Session["SearchResultsOrder"] = SearchResultsOrder; 
} 

El punto de esto es por lo tanto, cuando un usuario busca miembros, inicialmente se muestran en orden aleatorio, luego, si hacen clic en la página 2, permanecen en ese orden y se muestran los siguientes 20 resultados.

He estado leyendo sobre el ICompare que puedo usar como parámetro en la cláusula Linq.OrderBy, pero no puedo encontrar ningún ejemplo simple.

Espero una solución de estilo LINQ elegante y muy simple, así que siempre puedo esperar.

Cualquier ayuda es muy apreciada.

+4

¿Has considerado realizar una unión linq entre las dos listas y luego realizar una clasificación? – RQDQ

+0

Sugerencia: debe guardar el pedido original como diccionario: índice id 2. –

+3

Posible duplicado de http://stackoverflow.com/questions/3470098/linq-list-sort-based-on-another-list – goodeye

Respuesta

116

Otra LINQ enfoque:

var orderedByIDList = from i in ids 
         join o in objectsWithIDs 
         on i equals o.ID 
         select o; 
+0

¿Qué tan bueno es esto? –

+7

Mi experiencia personal es que, en general, Linq tiene un rendimiento mucho mejor de lo que mucha gente cree, en la mayoría de los casos es solo azúcar sintáctico que ejecuta las mismas operaciones que otros códigos al final, por lo que normalmente no notarás la diferencia. En realidad, para este caso especial solo sé que funciona, supongo que si no funciona bien, entonces tendrá que elegir una estructura de datos completamente diferente, porque esta lista completa siempre llevará algo de tiempo, sin importar cómo lo haga . –

24

Una forma de hacerlo:

List<int> order = ....; 
List<Item> items = ....; 

Dictionary<int,Item> d = items.ToDictionary(x => x.ID); 

List<Item> ordered = order.Select(i => d[i]).ToList(); 
+1

Está asumiendo que para cada int en la lista de pedidos, un artículo correspondiente existirá en los artículos list ... –

+1

'order.Where (d.ContainsKey) .Select (...)' o Select/SelectMany con una función más larga que usa TryGetValue resuelve ese problema. – Jimmy

9

Join es el mejor candidato si desea hacer coincidir el número entero exacto (si no hay partido que se encuentra obtener una secuencia vacía). Si simplemente desea obtener el orden de clasificación de la otra lista (y siempre que el número de elementos en ambas listas sea el mismo), puede usar Zip.

var result = objects.Zip(ints, (o, i) => new { o, i}) 
        .OrderBy(x => x.i) 
        .Select(x => x.o); 

Pretty legible.

+0

Nota importante: esto requiere que la lista 'ints' se ordene en primer lugar. La respuesta aceptada no. – Thorarin

+0

@Thorarin no, creo. ¿Por qué dices eso? Clasificamos 'ints' de todos modos para obtener el orden de clasificación, por lo que no es necesario que las entradas se ordenen en primer lugar. – nawfal

+0

@Thorarin, algo más está mal entonces. Estoy seguro de mi código :) – nawfal

4

Aquí hay un método de extensión que encapsula Simon D.'s response para listas de cualquier tipo.

public static IEnumerable<TResult> SortBy<TResult, TKey>(this IEnumerable<TResult> sortItems, 
                 IEnumerable<TKey> sortKeys, 
                 Func<TResult, TKey> matchFunc) 
{ 
    return sortKeys.Join(sortItems, 
         k => k, 
         matchFunc, 
         (k, i) => i); 
} 

uso es algo así como:

var sorted = toSort.SortBy(sortKeys, i => i.Key); 
13
No

una respuesta a esta exacta pregunta, pero si tiene dos matrices, hay una sobrecarga de Array.Sort que se lleva a la matriz para ordenar y una matriz que se utiliza como 'clave'

https://msdn.microsoft.com/en-us/library/85y6y2d3.aspx

Array.Sort Método (Array, Array)
Ordena un par de objetos unidimensionales array (uno contiene las teclas y el otro contiene los elementos correspondientes) basado en las llaves en la primera matriz utilizando la Implementación indivisible de cada clave.

+0

¿Alguna idea de cómo hacer que esto funcione para las listas? Estoy aquí ** porque ** tengo que trabajar con listas y no puedo usar esta clase de ordenamiento. – Bitterblue

0

Una posible solución:

myList = myList.OrderBy(x => Ids.IndexOf(x.Id)).ToList(); 

Nota: utilice esta opción si se trabaja con In-Memory listas, no funciona para IQueryable tipo, como IQueryable no contiene una definición para IndexOf

Cuestiones relacionadas