2012-05-16 3 views
2

Я работаю с API, который возвращает дубликаты идентификаторов. Мне нужно вставить эти значения в мою базу данных с помощью EF. Прежде чем пытаться добавить объекты, я хочу обрезать любые дубликаты.обрезать дубликаты с помощью Linq

У меня есть небольшой пример кода, который я пытаюсь написать.

var itemsToImport = new List<Item>(){}; 
     itemsToImport.Add(new Item() { Description = "D-0", Id = 0 });    
     for (int i = 0; i < 5; i++) 
     { 
      itemsToImport.Add(new Item(){Id = i,Description = "D-"+i.ToString()}); 
     } 

     var currentItems = new List<Item> 
         { 
          new Item() {Id = 1,Description = "D-1"}, 
          new Item(){Id = 3,Description = "D-3"} 
         }; 
     //returns the correct missing Ids 
     var missing = itemsToImport.Select(s => s.Id).Except(currentItems.Select(s => s.Id)); 


     //toAdd contains the duplicate record. 
     var toAdd = itemsToImport.Where(x => missing.Contains(x.Id)); 
     foreach (var item in toAdd) 
     { 
      Console.WriteLine(item.Description); 
     } 

Что мне нужно изменить, чтобы исправить мою переменную «toAdd», чтобы возвращать только одну запись, даже если есть повторение?

+0

У предметов с дублирующимися идентификаторами есть одинаковые данные? –

ответ

3

Вы можете сделать это, сгруппировавшись по идентификатору и выбрав первый элемент в каждой группе.

var toAdd = itemsToImport 
       .Where(x => missing.Contains(x.Id)); 

становится

var toAdd = itemsToImport 
       .Where(x => missing.Contains(x.Id)) 
       .GroupBy(item => item.Id) 
       .Select(grp => grp.First()); 
0

Вы можете использовать функцию Distinct. Вы должны переопределить Equals и GetHashCode в Item (учитывая, что они содержат одни и те же данные).

Или используйте FirstOrDefault, чтобы получить первый элемент с соответствующим идентификатором назад.

itemsToImport.Where(x => missing.Contains(x.Id)).FirstOrDefault() 
+0

таким образом вы получили бы только один предмет, а не целую коллекцию - вам не хватает groupBy? –

+0

Интерпретируя свой вопрос (я мог бы сделать это неправильно), он хочет, чтобы toAdd возвращал только одно значение. – Alex

2

Используйте DistinctBy из MoreLINQ, как это было рекомендовано Jon тарелочкам в https://stackoverflow.com/a/2298230/385844

на вызов будет выглядеть примерно так:

var toAdd = itemsToImport.Where(x => missing.Contains(x.Id)).DistinctBy(x => x.Id); 

Если вы хотите скорее, не (или не может) использовать MoreLINQ по какой-то причине, DistinctBy довольно легко реализовать:

static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> sequence, Func<T, TKey> projection) 
{ 
    var set = new HashSet<TKey>(); 
    foreach (var item in sequence) 
     if (set.Add(projection(item))) 
      yield return item; 
} 
Смежные вопросы