Получить список объектов, поле которых имеет максимальное значение

Предположим, у меня есть этот класс

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;
}

Мне не нужен первый, мне нужен список всех Лиц, чей возраст такой же, как у первого. Я пытаюсь найти однострочник для этого.

Daniel 17.02.2023 01:20
personArray.Where(p1=>p1.Age == personArray.Max(p2=>p2.Age)) Стрела с одним вкладышем
Dan Rayson 17.02.2023 01:22

@DanRayson просто из любопытства, я предполагаю, что при написании этого способа будет выполняться операция O (n) Max для каждого элемента, что приводит к O (n²). Я прав? Я не возражаю, так как мой список будет состоять только из 4 элементов, но это полезно знать.

Daniel 17.02.2023 01:26

Доказательство dotnetfiddle.net/OZAJqJ

Dan Rayson 17.02.2023 01:28

Понятия не имею, я бегу и вижу какого-то парня. Сказав это, linq может быть довольно умным. ChatGPT отвечает на вопрос «Вызовет ли personArray.Where(p1=>p1.Age == personArray.Max(p2=>p2.Age)) в C# linq операции O(n²)?» очень хорошо.

Dan Rayson 17.02.2023 01:29

@DanRayson, однострочник будет O (n²)

Kirill Polishchuk 17.02.2023 01:54

@KirillPolishchuk Только в том случае, если linq не компилируется в правильный запрос под капотом, что может быть. Если вы написали какой-нибудь linq для фреймворка сущностей, он скомпилирует его до разумной вещи, где он проверяет Макс только один раз, я ожидал бы от этого того же, хотя я не могу найти по нему никакой документации.

Dan Rayson 17.02.2023 11:20

@DanRayson, пример явно относится к объектам LINQ

Kirill Polishchuk 19.02.2023 20:38

@DanRayson, dotnetfiddle.net/XkMfm3

Kirill Polishchuk 19.02.2023 21:00

@KirillPolischuk Хорошая работа :) Я четко понял, что это linq к объектам xD

Dan Rayson 20.02.2023 09:43
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
10
62
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Один вариант будет

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();

отредактировано для этого

Jazz. 17.02.2023 01:21

Nitpick — я бы сначала сгруппировал, потом упорядочил по ключу, потом взял первую группу — думаю, так будет меньше сортировки.

D Stanley 17.02.2023 02:06

Сортировка O (N log (N)). Вы можете сделать это O (N) с помощью традиционного алгоритма цикла foreach или с помощью LINQ .Max

Flydog57 17.02.2023 03:39
Ответ принят как подходящий

Несколько вариантов для этого:

Опция 1


используя 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));

Вариант 2


используя 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/…

Martin 17.02.2023 01:53

Если вы ищете простой однострочный код и не возражаете против добавления внешней зависимости, у 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

Другие вопросы по теме