Предположим, у меня есть этот класс
public class Person {
public string name;
public int age;
//...
}
Предположим, у меня есть массив Person:
Person[] personArray;
Как я могу получить список людей с самым большим возрастом в personArray
, используя Linq?
Я пытаюсь это сделать, но мне жаль, что для выполнения этой задачи не было однострочника:
public List<Person> GetBiggestAgeList(){
var sortedPeople = personArray.OrderByDescending(person => person.age).ToList();
int maxAge = sortedPeople[0].age;
List<Person> answer = new List<Person>();
for(int i = 0; i < sortedPeople.Count; ++i){
if (sortedPeople[i].age == maxAge) answer.Add(sortedPeople[i]);
else break;
}
return answer;
}
personArray.Where(p1=>p1.Age == personArray.Max(p2=>p2.Age))
Стрела с одним вкладышем
@DanRayson просто из любопытства, я предполагаю, что при написании этого способа будет выполняться операция O (n) Max для каждого элемента, что приводит к O (n²). Я прав? Я не возражаю, так как мой список будет состоять только из 4 элементов, но это полезно знать.
Доказательство dotnetfiddle.net/OZAJqJ
Понятия не имею, я бегу и вижу какого-то парня. Сказав это, linq может быть довольно умным. ChatGPT отвечает на вопрос «Вызовет ли personArray.Where(p1=>p1.Age == personArray.Max(p2=>p2.Age))
в C# linq операции O(n²)?» очень хорошо.
@DanRayson, однострочник будет O (n²)
@KirillPolishchuk Только в том случае, если linq не компилируется в правильный запрос под капотом, что может быть. Если вы написали какой-нибудь linq для фреймворка сущностей, он скомпилирует его до разумной вещи, где он проверяет Макс только один раз, я ожидал бы от этого того же, хотя я не могу найти по нему никакой документации.
@DanRayson, пример явно относится к объектам LINQ
@DanRayson, dotnetfiddle.net/XkMfm3
@KirillPolischuk Хорошая работа :) Я четко понял, что это linq к объектам xD
Один вариант будет
var opa = personArray.OrderByDescending(x=>x.age).FirstOrDefault();
получить все опа
var allOpas = personArray.Where(x=>x.age == opa.age);
Один вкладыш будет:
var allOpas2 = personArray.OrderByDescending(x=>x.age).GroupBy(x=>x.age).FirstOrDefault().ToList();
отредактировано для этого
Nitpick — я бы сначала сгруппировал, потом упорядочил по ключу, потом взял первую группу — думаю, так будет меньше сортировки.
Сортировка O (N log (N)). Вы можете сделать это O (N) с помощью традиционного алгоритма цикла foreach
или с помощью LINQ .Max
Несколько вариантов для этого:
используя Linq .Max()
документацию
// structured
var max = personArray.Max(inner => inner.Age);
var list = personArray.Where(p => p.Age == max);
// ...or in an one-liner
var list = personArray.Where(p => p.Age == personArray.Max(inner => inner.Age));
используя Linq .GroupBy()
+ .FirstOrDefault()
документацию
// this will first order your list
// then group by all the ages and take the first group because this is the group of the persons with the highest age.
var list = personArray.OrderByDescending(p => p.Age)
.GroupBy(p => p.Age)
.FirstOrDefault()
.ToList();
Здесь вы можете найти рабочий пример dotnet fiddle
Я бы рекомендовал вариант 1 с
.Max()
более эффективным и быстрым, чем вариант 2, как вы можете видеть в скрипте dotnet. Чтобы это было действительно быстро, используйте Вариант 1 как два вкладыша и сначала разрешите.Max()
, а затем выполните.Where(..)
.
В конце концов, этот вопрос SO также может помочь: stackoverflow.com/questions/52850917/…
Если вы ищете простой однострочный код и не возражаете против добавления внешней зависимости, у MoreLINQ есть метод расширения (MaxBy
), который даст вам то, что вы ищете. Документация
var people = MoreLinq.MoreEnumerable.MaxBy(personArray, x => x.Age).ToArray();
В противном случае следующий однострочник сделает эту работу.
var people = personArray.Where(x => x.Age == personArray.Max(x => x.Age)).ToArray();
Другой вариант — разбить его на два запроса.
var max = personArray.Max(x => x.Age); // Find maximum age
var people = personArray.Where(x => x.Age == max).ToArray(); // Find people with maximum age
Мне не нужен первый, мне нужен список всех Лиц, чей возраст такой же, как у первого. Я пытаюсь найти однострочник для этого.