Как получить объект на основе 2-х критериев, не занимаясь расширенным поиском? - PullRequest
2 голосов
/ 23 октября 2011

Сложно описать это как вопрос в 1 строку. У меня есть такой класс:

class Item
{
    int Count {get; set;}
    double Value {get; set;}
}

и List<Item>, которые содержат произвольное число Item значений.

Как я могу получить Item с самым низким Count и самым высоким Value?

Производительность не важна, но элегантность такова, поскольку я не хочу иметь огромные вложенные циклы для выполнения этой операции, если нет элегантного способа, т. Е. Linq и т. Д.

EDIT:

Вот примерный список, который может иметь эти Items:

{Count, Value}

{2, 10}, {6, 60}, {5, 21}, {4, 65}, {2, 35}, {4, 18}, {3, 55}, {7, 99}, {2, 25}

Итак, здесь я хочу получить значение {2, 35}, поскольку оно имеет наименьшее значение Count из всех элементов, а для элементов с одинаковыми значениями Count оно имеет наибольшее значение Value.

.

Ответы [ 3 ]

5 голосов
/ 23 октября 2011

Хорошо, теперь у нас есть немного ясности:

, пока он имеет самый низкий счетчик, самое высокое значение в этом диапазоне - ОК

Это просто ...

var best = list.OrderBy(x => x.Count)
               .ThenByDescending(x => x.Value)
               .FirstOrDefault();

Это даст null, если список пуст, но в противном случае элемент с наименьшим количеством и элемент с наибольшим значением, если есть несколько с таким количеством.

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

1 голос
/ 23 октября 2011

С помощью morelinq (в котором есть операторы MinBy и MaxBy), вы можете легко выполнить это за линейное время (к сожалению, требуется дополнительный проход):

IEnumerable<item> items = ...

var minCount = items.Min(item => item.Count);
var minCountItemWithMaxValue = items.Where(item => item.Count == minCount)
                                    .MaxBy(item => item.Value);

С помощьюсоответствующее расширение AllMinBy, возвращающее все минимальное количество элементов в последовательности (к сожалению, отсутствует в morelinq), вы можете сделать это еще более эффективным:

var minCountItemWithMaxValue = items.AllMinBy(item => item.Count)
                                    .MaxBy(item => item.Value);

РЕДАКТИРОВАТЬ :

Вот (некрасивый) способ сделать это в O (1) пространстве и O (n) времени за один проход со стандартным LINQ:

var minCountItemWithMaxValue = items.Aggregate(
                                (bestSoFar, next) =>
                                (next.Count < bestSoFar.Count) ? next :  
                                (next.Count > bestSoFar.Count) ? bestSoFar :
                                (next.Value > bestSoFar.Value) ? next : bestSoFar);
1 голос
/ 23 октября 2011

Надеюсь, теперь это работает, к сожалению, не так элегантно, как у Джона

var res = (from i in items
           orderby i.Count ascending, i.Value descending
           select i).FirstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...