2012-02-10 68 views
0

我想基於過濾器表達式比較兩個列表;不知道如何構造泛型方法的lambda表達式;請參閱下面的代碼;還是有更簡單的方法通過LINQ中的相交?使用表達式/ lambda比較/過濾兩個列表的通用方法

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Data d1 = new Data {Id = 1, Name = "One"}; 
      Data d2 = new Data { Id = 2, Name = "Two" }; 
      Data d3 = new Data { Id = 3, Name = "Three" }; 

      Data d4 = new Data { Id = 1, Name = "One" }; 
      Data d5 = new Data { Id = 2, Name = "Two" }; 
      Data d6 = new Data { Id = 4, Name = "Four" }; 

      List<Data> original = new List<Data> {d1, d2, d3}; 
      List<Data> filterItems = new List<Data> {d4, d5, d6}; 

      List<Data> result = original.FilterDataList(filterItems); 

      //How to call this method? 
      List<Data> genericCall = original.FilterList<Data>(filterItems, data => data.Id ?????????????) 
     } 
    } 

    public class Data 
    { 
     public long Id; 
     public string Name; 
    } 

    public static class Extensions 
    { 
     public static List<Data> FilterDataList(this List<Data> sourceList, List<Data> filterOutItems) 
     { 
      return sourceList.Where(p => filterOutItems.All(l => l.Id != p.Id)).ToList(); 
     } 

     public static List<T> FilterList<T>(this List<T> sourceList, List<T> filterOutItems, Func<T, bool> filterExpression) 
     { 
      return sourceList.Where(p => filterOutItems.All(filterExpression)).ToList(); 
     } 
    } 
} 

回答

1

如果我正確理解您的問題,FilterListFilterDataList的通用版本,您將lambda作爲參數傳入。在這種情況下,你會調用該方法如下:

List<Data> genericCall = original.FilterList<Data>(filterItems, (x, y) => x.Id != y.Id); 

如果你想除非@ivancho和@perelman使用建議你可以使用這樣的方法:

public static class EnumerableExtension 
{ 
    public static IEnumerable<T> Except<T>(this IEnumerable<T> listA, IEnumerable<T> listB, 
              Func<T, T, bool> lambda) 
    { 
     return listA.Except(listB, new Comparer<T>(lambda)); 
    } 

    public static IEnumerable<T> Intersect<T>(this IEnumerable<T> listA, IEnumerable<T> listB, 
               Func<T, T, bool> lambda) 
    { 
     return listA.Intersect(listB, new Comparer<T>(lambda)); 
    } 
} 

,那麼你會叫它如下:

original.Except<Data>(filterItems, (x, y) => x.Id != y.Id); 
+0

啊哈! Except擴展正是我需要的!謝謝你:-)是的FilterList是一個通用的方法,我一直在努力,(x,y)=> x.Id!= y.Id不會與Func 一起工作,所以那裏我卡住了 – 2012-02-10 02:43:17

1

你想要的輸出是什麼?您是否嘗試過https://www.google.com/search?q=linq+intersect的第一個結果?看起來你應該通過Enumerable文檔 - 你正在使用的。所有你最可能的意思。任何,只是在一般情況下,它會讓你更好地瞭解LINQ的可能性。

1

我不清楚你在做什麼。您的FilterDataList看起來與Except().ToList()相同。您的FilterList中的.Where不使用p(lambda的參數),所以我不清楚您想要如何使用過濾器表達式。也許您正在尋找與Except()不同的IEqualityComparer,您必須將其定義爲單獨的類。

1

感謝大家的指點LINQ除延長了,這是我的最終解決方案

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Data d1 = new Data {Id = 1, Name = "One"}; 
      Data d2 = new Data { Id = 2, Name = "Two" }; 
      Data d3 = new Data { Id = 3, Name = "Three" }; 

      Data d4 = new Data { Id = 1, Name = "One" }; 
      Data d5 = new Data { Id = 2, Name = "Two" }; 


      List<Data> original = new List<Data> {d1, d2, d3}; 
      List<Data> filterItems = new List<Data> {d4, d5, d6}; 


      List<Data> datas = original.Except(filterItems, (x, y) => x.Id == y.Id).ToList(); 
     } 
    } 

    public class Data 
    { 
     public long Id; 
     public string Name; 
    } 

    public static class EnumerableExtension 
    { 
     public static IEnumerable<T> Except<T>(this IEnumerable<T> listA, IEnumerable<T> listB, 
               Func<T, T, bool> lambda) 
     { 
      return listA.Except(listB, new Comparer<T>(lambda)); 
     } 

     public static IEnumerable<T> Intersect<T>(this IEnumerable<T> listA, IEnumerable<T> listB, 
                Func<T, T, bool> lambda) 
     { 
      return listA.Intersect(listB, new Comparer<T>(lambda)); 
     } 
    } 


    public class Comparer<T> : IEqualityComparer<T> 
    { 
     private readonly Func<T, T, bool> _expression; 

     public Comparer(Func<T, T, bool> lambda) 
     { 
      _expression = lambda; 
     } 

     public bool Equals(T x, T y) 
     { 
      return _expression(x, y); 
     } 

     public int GetHashCode(T obj) 
     { 
      /* 
      If you just return 0 for the hash the Equals comparer will kick in. 
      The underlying evaluation checks the hash and then short circuits the evaluation if it is false. 
      Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects), 
      you will always fall through to the Equals check which is what we are always going for. 
      */ 
      return 0; 
     } 
    } 


}