Я пытаюсь вложить ключ максимального значения Dictionary<string, double> results
.
Это - то, что я имею до сих пор:
double max = results.Max(kvp => kvp.Value);
return results.Where(kvp => kvp.Value == max).Select(kvp => kvp.Key).First();
Однако, так как это кажется немного неэффективным, я задавался вопросом, был ли лучший способ сделать это.
Я думаю, что это наиболее читаемый ответ O (n) с использованием стандартного LINQ.
var max = results.Aggregate((l, r) => l.Value > r.Value ? l : r).Key;
править: объяснение CoffeeAddict
Aggregate
- это имя LINQ для общеизвестной функциональной концепции Fold
Он перебирает каждый элемент набора и применяет любую предоставленную вами функцию. {{1 }} Здесь предоставляемая мною функция представляет собой функцию сравнения, которая возвращает большее значение.
Во время цикла Aggregate
запоминает результат, возвращенный при последнем вызове моей функции. Он передает это в мою функцию сравнения как переменную l
. Переменная r
- это текущий выбранный элемент.
Таким образом, после того, как агрегат прошел цикл по всему набору, он возвращает результат самого последнего вызова моей функции сравнения. Затем я прочитал член .Key
из него, потому что я знаю, что это словарная статья
Вот другой способ взглянуть на это [я не гарантирую, что это компилируется;)]
var l = results[0];
for(int i=1; i<results.Count(); ++i)
{
var r = results[i];
if(r.Value > l.Value)
l = r;
}
var max = l.Key;
Возможно, это не лучший вариант для LINQ. Я вижу 2 полных сканирования словаря с помощью решения LINQ (1 для получения максимального значения, затем еще одного для поиска kvp для возврата строки.
Вы можете сделать это за 1 проход с помощью «старомодного» foreach:
KeyValuePair<string, double> max = new KeyValuePair<string, double>();
foreach (var kvp in results)
{
if (kvp.Value > max.Value)
max = kvp;
}
return max.Key;
Это быстрый метод. Это O(n), что является оптимальным. Единственная проблема, которую я вижу, это то, что итерации по словарю выполняются дважды, а не один раз.
Вы можете сделать итерацию по словарю один раз, используя MaxBy из morelinq.
results.MaxBy(kvp => kvp.Value).Key;
Я думаю, что, используя стандартные библиотеки LINQ, это настолько быстро, насколько это возможно.