Используйте 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();

Ответ 1

LINQ силен в запросе коллекций, создании прогнозов по существующим запросам или генерации новых запросов на основе существующих коллекций. Он не предназначен как инструмент для переопределения существующих коллекций. Для этого типа работы лучше всего использовать тип в руке.

Предполагая, что у вас есть тип с аналогичным определением, как показано ниже

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;

Ответ 2

Что вы хотите заказать, кроме известного верхнего элемента? Если вам все равно, вы можете сделать это:

var query = allCountries.OrderBy(x => x.id != 592).ToList();

В принципе, "false" предшествует "true"...

По общему признанию, я не знаю, что это делает в LINQ to SQL и т.д. Возможно, вам придется остановить его от выполнения заказа в базе данных:

var query = allCountries.AsEnumerable()
                        .OrderBy(x => x.id != 592)
                        .ToList();

Ответ 3

Linq обычно работает с Enumerables, поэтому теперь не является базовым типом коллекции. Поэтому для перемещения элемента в верхней части списка я бы предложил использовать что-то вроде (если вам нужно сохранить порядок)

var idx = myList.FindIndex(x => x.id == 592);
var item = myList[idx];
myList.RemoveAt(idx);
myList.Insert(0, item);

Если ваша функция возвращает только IEnumerable, вы можете использовать метод ToList(), чтобы преобразовать его в список сначала

Если вы не сохраняете заказ, вы можете просто поменять значения в позиции 0 и позиции idx

Ответ 4

var allCountries = repository.GetCountries();
allCountries.OrderByDescending(o => o.id == 12).ThenBy(o => o.id) 

Это будет вставлять объект с id = 12 в верхней части списка и поворачивать остальное вниз, сохраняя порядок.

Ответ 5

Вот метод расширения, который вы, возможно, захотите использовать. Он перемещает элемент (ы), который соответствует указанному предикату, сверху, сохраняя порядок.

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, но лучше, чем предложение Jon Skeet OrderBy.

Ответ 6

Вы можете "группировать по" в двух группах с булевым ключом, а затем сортировать их

var finalList= allCountries
                .GroupBy(x => x.id != 592)
                .OrderBy(g => g.Key)
                .SelectMany(g => g.OrderBy(x=> x.id ));

Ответ 7

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;
}

Ответ 8

Интересно, сколько подходов вы найдете при попытке решить проблему.

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);

Ответ 9

Я знаю, это старый вопрос, но я сделал это, как это

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

Ответ 10

Чтобы проверить, был ли элемент найден без исключения, что-то вроде:

var allCountries = repository.GetCountries();
var lookup = allCountries.ToLookup(x => x.id == 592);  
var finalList = lookup[true].Concat(looup[false]).ToList();
if ( lookup[true].Count != 1 ) YouAreInTrouble();