2010-11-01 102 views
5

對於兩個具有兩個不同類但公用字段的Lis​​t有可能使用Except()嗎?我有List<User1>List<User2>集合。他們有不同的屬性,除了Id列,我想使用此Id列找到他們之間的不同記錄。我試圖用List<>.Except()但我得到這個錯誤:具有公共字段的不同類之間的IEnumerable.Except()

The type arguments for method 'System.Linq.Enumerable.Except(System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable)' cannot be inferred from the usage. Try specifying the type arguments explicitly.

這裏的我想要什麼:

List<User1> list1 = List1(); 
List<User2> list2 = List2(); 
var listdiff = list1.Except(list2.Select(row => row.Id)); 

我在做什麼錯?

回答

9

List1包含User1的實例,List2包含User2的實例。

list1.Except(list2.Select(row => row.Id))應該生成什麼類型​​的實例? 換句話說,如果類型推斷不可用,你會用var替換什麼?

如果User1和User2從同一個祖先(帶ID)繼承,請改爲使用List<User>

否則:

var list2Lookup = list2.ToLookup(user => user.Id); 
var listdiff = list1.Where(user => (!list2Lookup.Contains(user.Id)) 
+1

+1如果你做出'list2',而不是'list1'查找。或者沒有查找var listdiff = list1.Where(user =>!(list2.Any(user2 => user2.Id == user.Id));' – 2010-11-01 16:19:03

+0

Yup注意到幾分鐘前的錯誤 – 2010-11-01 16:20:43

+0

+1:好東西,效率也會很高。 – Ani 2010-11-01 16:26:36

3

簡而言之,使列表爲List<object>並使用.NET 4.0的C#功能:dynamic

例子:

var listDiff = list1 
    .AsEnumerable<object>() 
    .Except(list2 
     .AsEnumerable<object>() 
     .Select(row => ((dynamic)row).ID)); 
+0

對不起忘了補充一點,我使用的是V3.5 – dstr 2010-11-02 09:55:06

2

如果你只是想在list1Ids不在list2,你可以這樣做:

var idsInList1NotInList2 = list1.Select(user1 => user1.Id) 
           .Except(list2.Select(user2 => user2.Id)); 

如果您需要相關User1對象了,這裏有一個方法(假設Ids對於User1對象是唯一的):

// Create lookup from Id to the associated User1 object 
var user1sById = list1.ToDictionary(user1 => user1.Id); 

// Find Ids from the lookup that are not present for User2s from list2 
// and then retrieve their associated User1s from the lookup 
var user1sNotInList2 = user1sById.Keys 
           .Except(list2.Select(user2 => user2.Id)) 
           .Select(key => user1sById[key]); 

編輯:vc74的採取這個想法稍好;它不需要唯一性。

4

Except,但正確的結果和相似的性能:

// assumes that the Id property is an Int32 
var tempKeys = new HashSet<int>(list2.Select(x => x.Id)); 
var listdiff = list1.Where(x => tempKeys.Add(x.Id)); 

,當然,你可以在自己的可重複使用的擴展方法包裝了這一切:

var listdiff = list1.Except(list2, x => x.Id, y => y.Id); 

// ... 

public static class EnumerableExtensions 
{ 
    public static IEnumerable<TFirst> Except<TFirst, TSecond, TKey>(
     this IEnumerable<TFirst> first, 
     IEnumerable<TSecond> second, 
     Func<TFirst, TKey> firstKeySelector, 
     Func<TSecond, TKey> secondKeySelector) 
    { 
     // argument null checking etc omitted for brevity 

     var keys = new HashSet<TKey>(second.Select(secondKeySelector)); 
     return first.Where(x => keys.Add(firstKeySelector(x))); 
    } 
} 
2
public static IEnumerable<TSource> Except<TSource, CSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> TSelector, IEnumerable<CSource> csource, Func<CSource, TKey> CSelector) 
    { 
     bool EqualFlag = false; 
     foreach (var s in source) 
     { 
      EqualFlag = false; 
      foreach (var c in csource) 
      { 
       var svalue = TSelector(s); 
       var cvalue = CSelector(c); 
       if (svalue != null) 
       { 

        if (svalue.Equals(cvalue)) 
        { 
         EqualFlag = true; 
         break; 
        } 
       } 
       else if (svalue == null && cvalue == null) 
       { 
        EqualFlag = true; 
        break; 
       } 
      } 
      if (EqualFlag) 
       continue; 
      else 
      { 
       yield return s; 
      } 
     } 

    } 
0

嘗試

list1.Where(user1 => !list2.Any(user2 => user2.Id.Equal(user1.Id))); 
+0

歡迎來到[so]!爲什麼這個工作?那些能夠自己回答這個問題的人可能不需要別人的代碼。 – jpaugh 2017-08-10 18:06:10

相關問題