使用表达式/lambda比较/筛选两个列表的泛型方法

本文关键字:两个 列表 泛型方法 表达式 lambda 比较 筛选 | 更新日期: 2023-09-27 18:24:11

我想根据一个筛选表达式比较两个列表;不确定如何为泛型方法构造lambda表达式;请参阅以下代码;或者在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" };
            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();
        }
    }
}

使用表达式/lambda比较/筛选两个列表的泛型方法

感谢大家指出LINQ Except扩展,这是我的最终解决方案

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;
        }
    }

}

如果我正确理解您的问题,FilterListFilterDataList的通用版本,您将lambda作为参数传入。在这种情况下,您将按如下方式调用该方法:

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

如果你想使用Except,就像@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);

您想要的输出是什么?你试过第一个结果吗https://www.google.com/search?q=linq+相交?似乎你应该浏览一下你正在使用的Enumerable文档。所有你最可能的意思都是。任何,总的来说,它会让你更好地了解LINQ的可能。

我不清楚你想做什么。你的FilterDataList似乎和Except() .ToList()一样。FilterList中的.Where不使用p(lambda的参数),所以我不清楚您想对筛选器表达式做什么。也许您正在寻找将不同的IEqualityComparerExcept()一起使用,您必须将其定义为一个单独的类。