简体   繁体   English

使用表达式/ lambda比较/过滤两个列表的通用方法

[英]Generic method to compare/filter two lists using expressions/lambda

I want to compare two lists, based on a filter expression; 我想根据过滤器表达式比较两个列表; not sure how to construct the lambda expression for the generic method; 不知道如何为泛型方法构造lambda表达式; Please refer to the code below; 请参考下面的代码; or is there an easier way via an intersect in LINQ? 还是通过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();
        }
    }
}

What is your desired output? 您想要的输出是什么? Did you try the first result in https://www.google.com/search?q=linq+intersect ? 您是否在https://www.google.com/search?q=linq+intersect中尝试了第一个结果? It seems like you should go through the Enumerable documentation - you are using .All where you most likely mean .Any, and just in general it would give you a better idea of what is possible with LINQ. 似乎您应该遍历Enumerable文档-您正在使用.All,最有可能是.Any,一般而言,它可以使您更好地了解LINQ的可能。

I am not clear what you are trying to do. 我不清楚您要做什么。 Your FilterDataList appears to be the same as Except() .ToList() . 您的FilterDataList似乎与Except() .ToList() The .Where in your FilterList does not use p (the argument to the lambda), so I am unclear what you want to do with the filter expression. FilterList中的.Where不使用p (lambda的参数),因此我不清楚要对过滤器表达式执行的操作。 Maybe you are looking for using a different IEqualityComparer with Except() which you would have to define as a separate class. 也许您正在寻找对Except()使用不同的IEqualityComparer ,但必须将其定义为单独的类。

If I understand your question correctly, FilterList is a generic version of FilterDataList where you are passing in the lambda as a parameter. 如果我正确理解您的问题,则FilterListFilterDataList的通用版本,您在其中将lambda作为参数传递。 In that case you would call the method as follows: 在这种情况下,您可以按以下方式调用方法:

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

If you want to use Except as @ivancho and @perelman have suggested you could use a method like this: 如果您想将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));
    }
}

You would then call it as follows: 然后,您将其称为如下:

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

Thanks to everyone for pointing the LINQ Except extension out, here is my end solution 感谢所有人指出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;
        }
    }


}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM