Сортировать список и выбрать объект по порядку - PullRequest
2 голосов
/ 27 марта 2019

У меня есть List<MyClass> с Status и Date полями. Я хочу вернуть один MyClass, где Status = X.

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

Можно ли это сделать в LINQ в одном выражении?

Ответы [ 3 ]

3 голосов
/ 27 марта 2019

Вы можете использовать лямбда-выражение:

var yourResult = dbo.YourList.OrderByDescending(t=>t.Date).FirstOrDefault(t=>t.Status == 'X');
1 голос
/ 27 марта 2019

Если list уже находится в памяти, попробуйте это:

var answer = list.Where(x => x.Status == X).OrderBy(x => x.Date).LastOrDefault();

В случае Entity Framework попробуйте другой подход:

var answer = context.Table.Where(x => x.Status == X).OrderByDescending(x => x.Date).FirstOrDefault();
0 голосов
/ 28 марта 2019

Итак, вы последовательность MyClass объектов и объект X, и вы хотите найти новейший MyClass объект, значение которого для Status равно X

var result = myList.Where(myItem => myItem.Status == X)
                   .OrderByDescending(myItem => myItem.Date)
                   .FirstOrDefault();

Хотя это будет работать, сортировка не очень эффективна: после того, как вы найдете первый элемент, он сортирует 2-й, 3-й и т. Д., Хотя вы знаете, что они не будут использовать эти другие элементы, так зачем их сортировать?Если вы используете Aggregate, вам нужно будет только перечислить один раз

var result = myList.Where(...)
    .Aggregate( (newestItem, nextItem) => (newestItem.Date < nextItem.Date) ? 
           newestItem : nextItem);

Это помещает первый элемент в newestItem и сканирует остальную часть списка.Если какой-либо nextItem имеет новые данные, поместите этот следующий элемент в newestItem, в противном случае не изменяйте newestItem.В конце верните newestItem, который с самой новой датой, которую вы хотите.

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

static TResult GetNewestOrDefault<TSource, TResult>(this IEnumerable<TSource> source,
   Func<Tsource, DateTime> dateSelector)
{
    var enumerator = source.GetEnumerator();

    if (enumerator.MoveNext())
    {   // at least one element; initialize newest:
        TSource newestElement = enumerator.Current;
        DateTime newestDate = dateSelector(newest);

        // scan the rest of the sequence and check if newer:
        while (enumerator.MoveNext())
        {
            Tsource nextElement = enumerator.Current;
            Datetime nextDate = dateSelector(nextElement);

            // if next element has a newer date, remember it as newest:

            if (newestDate < nextDate
            {
                newestElement = nextElement;
                newestDate = nextDate,
            }
        }
        // scanned all elements exactly once
        return newestElement;
    }
    else
       // empty sequence, return default
       return default(TResult);
}

Использование:

MyClass result = myList.Where(myItem => myItem.Status == X)
                       .GetNewestOrDefault();

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...