¿Hay alguna forma de mover un elemento de, por ejemplo, id = 10 como el primer elemento de una lista usando LINQ?
Artículo A - id = 5 Artículo B - id = 10 Elemento C - id = 12 Elemento D - id = 1
En este caso, ¿cómo puedo mover elegantemente el artículo C a la parte superior de mi List<T>
colección?
Esto es lo mejor que tengo ahora mismo:
var allCountries = repository.GetCountries();
var topitem = allCountries.Single(x => x.id == 592);
var finalList = new List<Country>();
finalList.Add(topitem);
finalList = finalList.Concat(allCountries.Where(x=> x.id != 592)).ToList();
Respuestas:
LINQ es fuerte para consultar colecciones, crear proyecciones sobre consultas existentes o generar nuevas consultas basadas en colecciones existentes. No pretende ser una herramienta para reordenar colecciones existentes en línea. Para ese tipo de operación, es mejor usar el tipo a mano.
Suponiendo que tiene un tipo con una definición similar a la siguiente
class Item { public int Id { get; set; } .. }
Entonces intente lo siguiente
List<Item> list = GetTheList(); var index = list.FindIndex(x => x.Id == 12); var item = list[index]; list[index] = list[0]; list[0] = item;
fuente
FindIndex
valor del resultado, es -1 si el elemento no se encuentra en la lista.¿Por qué desea ordenar, además del artículo superior conocido? Si no le importa, puede hacer esto:
var query = allCountries.OrderBy(x => x.id != 592).ToList();
Básicamente, "falso" viene antes que "verdadero" ...
Es cierto que no sé qué hace esto en LINQ to SQL, etc. Es posible que deba evitar que haga el pedido en la base de datos:
var query = allCountries.AsEnumerable() .OrderBy(x => x.id != 592) .ToList();
fuente
Name
lista pequeña en la parte superior o en el índice 0, en LINQ to Entities, y funcionó gracias +1.db.Systms.Where(s => s.IsActive == true).OrderBy(x => x.SystemName != "Portal Administration").ToList();
Linq generalmente trabaja en Enumerables, por lo que no lo hace ahora que el tipo subyacente es una colección. Entonces, para mover el elemento en la parte superior de la lista, sugeriría usar algo como (si necesita preservar el orden)
var idx = myList.FindIndex(x => x.id == 592); var item = myList[idx]; myList.RemoveAt(idx); myList.Insert(0, item);
Si su función devuelve solo un IEnumerable, puede usar el
ToList()
método para convertirlo en una Lista primeroSi no conserva el orden, simplemente puede intercambiar los valores en la posición 0 y la posición idx
fuente
var allCountries = repository.GetCountries(); allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id)
Esto insertará el objeto con id = 12 en la parte superior de la lista y rotará el resto hacia abajo, preservando el orden.
fuente
A continuación, se muestra un método de extensión que quizás desee utilizar. Mueve los elementos que coinciden con el predicado dado a la parte superior, conservando el orden.
public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) { return list.Where(func) .Concat(list.Where(item => !func(item))); }
En términos de complejidad, creo que haría dos pases en la colección, haciéndola O (n), como la versión Insertar / Eliminar, pero mejor que la sugerencia OrderBy de Jon Skeet.
fuente
Puede "agrupar por" en dos grupos con la clave booleana y luego ordenarlos
var finalList= allCountries .GroupBy(x => x.id != 592) .OrderBy(g => g.Key) .SelectMany(g => g.OrderBy(x=> x.id ));
fuente
Sé que esta es una vieja pregunta pero lo hice así
class Program { static void Main(string[] args) { var numbers = new int[] { 5, 10, 12, 1 }; var ordered = numbers.OrderBy(num => num != 10 ? num : -1); foreach (var num in ordered) { Console.WriteLine("number is {0}", num); } Console.ReadLine(); } }
esto imprime:
el número es 10 el
número es 1 el
número es 5 el
número es 12
fuente
public static IEnumerable<T> ServeFirst<T>(this IEnumerable<T> source, Predicate<T> p) { var list = new List<T>(); foreach (var s in source) { if (p(s)) yield return s; else list.Add(s); } foreach (var s in list) yield return s; }
fuente
Es interesante la cantidad de enfoques que encuentras cuando intentas resolver un problema.
var service = AutogateProcessorService.GetInstance(); var allConfigs = service.GetAll(); allConfigs = allConfigs.OrderBy(c => c.ThreadDescription).ToList(); var systemQueue = allConfigs.First(c => c.AcquirerId == 0); allConfigs.Remove(systemQueue); allConfigs.Insert(0, systemQueue);
fuente
Para verificar también si el elemento se encontró sin excepción, algo como:
var allCountries = repository.GetCountries(); var lookup = allCountries.ToLookup(x => x.id == 592); var finalList = lookup[true].Concat(lookup[false]).ToList(); if ( lookup[true].Count() != 1 ) YouAreInTrouble();
fuente
Escribí un método de extensión estática para hacer esto. Tenga en cuenta que esto no conserva el orden, simplemente intercambia el artículo. Si necesita conservar el orden, debe hacer una rotación, no un simple intercambio.
/// <summary> /// Moves the item to the front of the list if it exists, if it does not it returns false /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="predicate"></param> /// <returns></returns> public static bool MoveToFrontOfListWhere<T>(this List<T> collection, Func<T, bool> predicate) { if (collection == null || collection.Count <= 0) return false; int index = -1; for (int i = 0; i < collection.Count; i++) { T element = collection.ElementAt(i); if (!predicate(element)) continue; index = i; break; } if (index == -1) return false; T item = collection[index]; collection[index] = collection[0]; collection[0] = item; return true; }
fuente