Выборочная сортировка с помощью LINQ - PullRequest
2 голосов
/ 18 сентября 2009

Кажется, мне не хватает чего-то тривиального.

Так или иначе, вот оно:

var order = new[]{1,3,2};
var foos = new[]{new Foo{Id=1}, new Foo{Id=2}, new Foo{Id=3}};

Как отсортировать foos по порядку массивов с помощью Linq?

Желаемый результат:

foos == new[]{new Foo{Id=1}, new Foo{Id=3}, new Foo{Id=2}};

Edit:
Заказ содержит идентификаторы Foo. Извините, что я не упомянул это. Иногда еще сложнее правильно задать вопрос, чем ответить на него. :)

Ответы [ 6 ]

4 голосов
/ 18 сентября 2009

Это то, что вы пытаетесь сделать?

foos.OrderBy(f => order[f.Id-1]);

Если вы теперь выводите вывод, печатая ID, вы получите: 1,3,2

3 голосов
/ 18 сентября 2009

Хорошо, вопрос, похоже, не полностью понятен мне, поэтому я попытаюсь уточнить, что я думаю вы спрашиваете:

  • У вас есть последовательность идентификаторов, в нужном порядке
  • У вас есть коллекция объектов, не в правильном порядке, но с соответствующими идентификаторами
  • Вы хотите получить коллекцию объектов в том же порядке, что и последовательность идентификаторов

Правильно?

Это было бы:

var orderedFoos = from orderedId in order
                  join foo in foos on orderedId equals foo.Id into groups
                  select groups.Single();

Вам нужно join ... into, чтобы убедиться, что у вас нет пропущенных или дублирующих идентификаторов в foos. Однако он не обнаружит, есть ли у вас пропущенные или повторяющиеся идентификаторы в order. Если вы знаете, что все будет правильно (т. Е. Будет ровно одна запись в foos для каждой записи в order и наоборот), тогда можно выполнить простое объединение:

var orderedFoos = from orderedId in order
                  join foo in foos on orderedId equals foo.Id
                  select foo;

, которое может быть выражено в точечной записи как:

var orderedFoos = order.Join(foos, order => order, foo => foo.ID, (o, f) => f);
3 голосов
/ 18 сентября 2009
from o in order.Select((o, i) => new { o, i })
join f in foos on o.o equals f.Id
orderby o.i
select f;
1 голос
/ 18 сентября 2009

Вы можете сделать это, используя вложенный запрос, но он довольно неэффективен с O(n²).

var result = order.Select(o => foos.Single(f => f.Id == o));

Если 'order' может содержать идентификаторы, отсутствующие в 'foos', вы должны использовать SingleOrDefault(). Если foos может содержать повторяющиеся идентификаторы, вы должны использовать First() или FirstOrDefault().

var result = order
    .Select(o => foos.FirstOrDefault(f => f.Id == o))
    .Select(f => f != null);

Может быть, даже объединение будет работать, но я не уверен, сохранит ли он порядок.

var result = Enumerable.Join(order, foos, o => o, f => f.Id, (o, f) => f);

Как упоминал Джон, объединение будет работать корректно, только если вход правильно сформирован так же, как того требует мое первое предложение.

1 голос
/ 18 сентября 2009

Я бы, вероятно, использовал бы Dictionary<int,int> пар id / упорядочения для поиска порядка O (1), если бы у меня было много таких задач. Обратите внимание, что вам также нужно будет обработать случаи, когда ваши значения отсутствуют в порядке - я решил переместить их в конец.

var order = new Dictionary<int,int>();
order.Add( 1, 1 );
order.Add( 2, 3 );
order.Add( 3, 2 );

var orderedFoos = foos.OrderBy( f => order.Contains(f.Id) ? order[f.Id] : int.MaxValue );
0 голосов
/ 18 сентября 2009
var order = new[] { 1, 3, 2 };
var foos = new[] { new Foo { Id = 1 }, new Foo { Id = 2 }, new Foo { Id = 3 } };

var query = from o in order
            join foo in foos on o equals foo.Id
            select foo;

var foos2 = query.ToArray();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...