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

发布于 2025-01-04 00:56:29 字数 1607 浏览 0 评论 0原文

我想根据过滤表达式比较两个列表;不确定如何构造泛型方法的 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();
        }
    }
}

I want to compare two lists, based on a filter expression; not sure how to construct the lambda expression for the generic method; Please refer to the code below; or is there an easier way via an intersect in 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();
        }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

荒人说梦 2025-01-11 00:56:29

感谢大家指出 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;
        }
    }


}

Thanks to everyone for pointing the LINQ Except extension out, here is my end solution

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


}
那伤。 2025-01-11 00:56:29

如果我正确理解您的问题,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);

If I understand your question correctly, FilterList is a generic version of FilterDataList where you are passing in the lambda as a parameter. 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:

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);
厌味 2025-01-11 00:56:29

您想要的输出是什么?您是否尝试过 https://www.google.com/search?q= 中的第一个结果linq+相交?看来您应该仔细阅读 Enumerable 文档 - 您正在使用 .All 您最有可能指的是 .Any,并且一般来说它会让您更好地了解 LINQ 的可能性。

What is your desired output? Did you try the first result in 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.

雨落星ぅ辰 2025-01-11 00:56:29

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

I am not clear what you are trying to do. Your FilterDataList appears to be the same as 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. Maybe you are looking for using a different IEqualityComparer with Except() which you would have to define as a separate class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文