2016-06-28 2 views
3

У меня есть List из Document объектов. Класс Document имеет много свойств, но здесь всего два, DocumentLinkId и UploadedOnDate.Как я могу использовать Distinct для определенного свойства и выбрать объект для сохранения на основе предиката?

Что я хочу сделать, это отфильтровать список, так что нет двух объектов Document с одинаковыми DocumentLinkId. Когда есть более одного объекта Document с конкретным DocumentLinkId Я хочу сохранить его с последним UploadedOnDate.

Мой первоначальный наклон был сделать что-то вроде этого:

myDocumentsList.Distinct(d => d.DocumentLinkId).Max(d => d.UploadedOnDate); 

Но Distinct() не принимает предикат. Есть ли способ сделать это с помощью LINQ?

+0

Попытка группировки с помощью 'DocumentLinkId', а затем взятие одной в каждой группе с max' UploadedOnDate' – Nkosi

+0

Всегда существует опция (старая школа) для записи цикла for с типом Dictionary Как кэш. Скорее всего, он будет работать быстрее и будет легче отлаживать, если что-то пойдет не так, или вы хотите расширить критерии поиска и т. П. – Neolisk

ответ

8

Вы можете сгруппировать документы по DocumentLinkId, и для каждой группы, выберите элемент с последним UploadedOnDate, как это:

var result = myDocumentsList 
    .GroupBy(d => d.DocumentLinkId) 
    .Select(g => g.OrderByDescending(d => d.UploadedOnDate).First()) 
    .ToList(); 
+0

Это генерирует исключение с сообщением 'Метод 'First' может использоваться только как конечная операция запроса. Вместо этого рассмотрите использование метода «FirstOrDefault» в этом случае. « – Legion

+0

Используете ли вы LINQ для объектов? Замените 'First' на' FirstOrDefault'. –

+0

В этом случае да. – Legion

1

Вы можете использовать DistinctBy как в this question.

var query = people.DistinctBy (p => p.Id);

Это будет что-то вроде:

myDocumentsList.OrderByDescending(x => x.UploadedOnDate).ToList().DistinctBy(d => d.DocumentLinkId).Max(d => d.UploadedOnDate); 

для вашего дела.

+0

Сначала выберете набор документов с отличным 'DocumentLinkId'. когда он выбирает их, он может или не может выбирать те, у которых самый последний «UploadedOnDate». Затем, создав этот набор, он выберет только один документ с самым высоким 'UploadedOnDate'. Поэтому он не возвращает отдельный набор. Он возвращает один объект. –

+0

Вы правы @ScottHannen Я обновил свой ответ, чтобы выбрать записи в списке, сначала упорядоченные с помощью UploadedOnDate, а затем, чтобы выделить их, отличные от DocumentLinkId – meJustAndrew

1

Вы можете определить реализацию IEqualityComparer<Document>. Он существует практически для этого сценария.

public class DocumentLinkIdDocumentEqualityComparer : IEqualityComparer<Document> 
{ 
    public bool Equals(Document document1, Document document2) 
    { 
     return document1.DocumentLinkId == document2.DocumentLinkId; 
    } 
} 

Тогда вы можете сделать это:

myDocumentsList.OrderByDescending(d => d.UploadedOnDate) 
    .Distinct(new DocumentLinkIdDocumentEqualityComparer()) 

(. Пришлось изменить это заказать его первый, так что различные возвращает один с наиболее свежей датой)

Вы говорите, что для этого сравнения Distinct, воспользуемся этим компаратором и действуем так, как будто любые два документа с одинаковыми DocumentLinkId равны.

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

+0

Я думаю, что это должен быть 'return document1.DocumentLinkId == document2.DocumentLinkId;' Нужно == – Legion

+0

Да, спасибо. Это то, что происходит, когда я кодирую непосредственно в редакторе ответов. –

Смежные вопросы