Использовать LINQ, чтобы переместить элемент на верхней части списка
есть ли способ переместить элемент say id=10 в качестве первого элемента в списке с помощью LINQ?
Item A - id =5 Item B - id = 10 Item C - id =12 Item D - id =1
в этом случае как я могу элегантно переместить элемент C в верхнюю часть моего List<T>
коллекция?
Это лучшее, что у меня сейчас есть:
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();
11 ответов:
LINQ сильна в запросе коллекций, создании проекций по существующим запросам или создании новых запросов на основе существующих коллекций. Он не предназначен в качестве инструмента для переупорядочения существующих коллекций inline. Для этого типа операции лучше всего использовать тип в hande.
предполагая, что у вас есть тип с аналогичным определением, как показано ниже
class Item { public int Id { get; set; } .. }
затем попробуйте следующее
List<Item> list = GetTheList(); var index = list.FindIndex(x => x.Id == 12); var item = list[index]; list[index] = list[0]; list[0] = item;
что вы хотите заказать, кроме известного верхнего элемента? Если вам все равно, вы можете сделать это:
var query = allCountries.OrderBy(x => x.id != 592).ToList();
в основном, " ложь "предшествует"истине"...
по общему признанию, я не знаю, что это делает в LINQ to SQL и т. д. Возможно, вам придется остановить его от выполнения заказа в базе данных:
var query = allCountries.AsEnumerable() .OrderBy(x => x.id != 592) .ToList();
Linq обычно работает с перечисляемыми, поэтому теперь он не является базовым типом коллекции. Поэтому для перемещения элемента в верхней части списка я бы предложил использовать что-то вроде (Если вам нужно сохранить порядок)
var idx = myList.FindIndex(x => x.id == 592); var item = myList[idx]; myList.RemoveAt(idx); myList.Insert(0, item);
Если ваша функция возвращает объект IEnumerable, вы можете использовать
ToList()
метод, чтобы преобразовать его в список первыхЕсли вы не сохраняете порядок, вы можете просто поменять значения в позиции 0 и позиции idx
var allCountries = repository.GetCountries(); allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id)
Это позволит вставить объект с id=12 в верхней части списка и повернуть остальные вниз, сохраняя порядок.
вот метод расширения, который вы можете использовать. Он перемещает элементы, соответствующие заданному предикату, в верхнюю часть, сохраняя порядок.
public static IEnumerable<T> MoveToTop(IEnumerable<T> list, Func<T, bool> func) { return list.Where(func) .Concat(list.Where(item => !func(item))); }
С точки зрения сложности, я думаю, что он сделает два прохода по коллекции, сделав ее O(n), как версия Insert/Remove, но лучше, чем предложение OrderBy Джона Скита.
вы можете "сгруппировать" в две группы с Булевым ключом, а затем отсортировать их
var finalList= allCountries .GroupBy(x => x.id != 592) .OrderBy(g => g.Key) .SelectMany(g => g.OrderBy(x=> x.id ));
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; }
его интересно количество подходов, которые вы найдете при попытке решить проблему.
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);
Я знаю, что это старый вопрос, но я сделал это так
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(); } }
печатается:
номер 10
число 1
число 5
число 12
Я написал статический метод расширения для этого. Обратите внимание, что это не сохраняет заказ, он просто меняет элемент. Если вам нужно было сохранить порядок, вы должны сделать поворот не простой своп.
/// <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; }