Выборочное упорядочивание с LINQ, частичное упорядочивание

Скажем, у меня есть список объектов:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = -1 },
    new { Order = 3 },
    new { Order = 2 },
    new { Order = -1 }
};

Я должен заказать его так, чтобы объекты с Order > -1 будьте сверху списка, заказанного возрастанием Порядка и остающимися объектами с Order == -1 следовали за ними.

Есть ли более изящный способ сделать это, чем использование Conact() и Where() пункты:

var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
                   .Conact(items.Where(x => x.Order == -1);

Так, чтобы после сортировки этого списка был бы похож:

var items = new {
    new { Order = 0 },
    new { Order = 1 },
    new { Order = 2 },
    new { Order = 3 },
    new { Order = -1 },
    new { Order = -1 }
};

Также items список в фактическом сценарии уже является комплексом IQueryable<T> объект. Вот почему я пытаюсь найти самый оптимальный способ сделать такое выборочное упорядочивание.

5
задан double-beep 9 February 2019 в 18:55
поделиться

6 ответов

Вы можете попробовать следующее - это даст ожидаемый результат:

items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);
7
ответ дан 18 December 2019 в 09:07
поделиться

Если вы упорядочиваете по возрастанию, -1 уже должно быть вверху списка, потому что это наименьшее значение.

Однако в более общем плане, если вы все еще хотите применить другую сортировку к подмножествам данных, я не думаю, что было бы более элегантный способ, потому что это именно то, что вы делаете, и объединение логически точное. Вы пытаетесь извлечь два отдельных подмножества данных, отсортировать их по-разному, а затем объединить их вместе, что является одной из вещей, для которых я должен использовать объединение.

3
ответ дан 18 December 2019 в 09:07
поделиться

Как отметил Майк, в вашем примере это будет работать автоматически, но, скажем, мы хотим сначала получить все -1 элементы, а затем отсортировать оставшиеся элементы в порядке убывания. Это можно сделать с помощью одного замечательного трюка. Вы можете использовать несколько ключей при упорядочивании элементов. Первым ключом может быть булево значение, которое будет false для всех значений -1 (поэтому они будут первыми) и true для всех остальных значений (поэтому они не будут переупорядочены). Вторым ключом может быть любое значение, которым вы хотите упорядочить оставшиеся элементы. Например:

var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
        orderby n != -1, n descending
        select n;

Сначала будут получены все значения, для которых n != -1 и false, а затем все элементы, упорядоченные с помощью n по убыванию, так что вы получите:

-1, -1, 7, 4, 4, 3, 2

Это работает в общем случае, когда вам нужно обрабатывать некоторые элементы особенно в упорядочении - вам просто нужно предоставить правильные ключи упорядочения.

6
ответ дан 18 December 2019 в 09:07
поделиться

Используйте настраиваемый компаратор , чтобы определить желаемый порядок.

public class MyComparer : IComparer<int>
{
    public int Compare(int a, int b)
    {
        if ((a < 0) && (b >= 0))
        {
            return 1;
        }
        if ((a >= 0) && (b < 0))
        {
            return -1;
        }
        return int.Compare(a, b);
    }
}

Тогда вы можете сделать:

var orderedItems = items.OrderBy(x => x.Order, new MyComparer());
0
ответ дан 18 December 2019 в 09:07
поделиться

Также здесь можно использовать настраиваемый компаратор, если вы хотите, чтобы -1 отображался первым, а остальные должны быть по убыванию , но почему-то я считаю его более элегантным :) Обратите внимание, что он сделан для ints

class Comparer : IComparer<int>
{
  public int Compare(int x, int y)
  {
    if (x == -1 || y == -1) return x - y;
    return y - x;
  }
}
1
ответ дан 18 December 2019 в 09:07
поделиться
OrderBy(x => x.Order < 0 ? int.MaxValue : x.Order)

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

OrderBy(x => x.Order < 0 ? (long)int.MaxValue - x.Order : (long)x.Order)
1
ответ дан 18 December 2019 в 09:07
поделиться
Другие вопросы по тегам:

Похожие вопросы: