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

时间:2012-02-10 02:22:27

标签: c# .net linq generic-list

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

4 个答案:

答案 0 :(得分:1)

您想要的输出是多少?你在https://www.google.com/search?q=linq+intersect尝试了第一个结果吗?看起来你应该浏览一下Enumerable文档 - 你正在使用。所有你最有可能的意思.Any,一般来说它会让你更好地了解LINQ的可能性。

答案 1 :(得分:1)

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

答案 2 :(得分:1)

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

答案 3 :(得分:1)

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


}