Общий метод для сравнения / фильтрации двух списков с использованием выражений / лямбда - PullRequest
0 голосов
/ 10 февраля 2012

Я хочу сравнить два списка на основе выражения фильтра;не уверен, как построить лямбда-выражение для универсального метода;Пожалуйста, обратитесь к коду ниже;или есть более простой способ через пересечение в 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 ]

1 голос
/ 13 февраля 2012

Спасибо всем за то, что указали расширение 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;
        }
    }


}
1 голос
/ 10 февраля 2012

Мне не ясно, что вы пытаетесь сделать.Ваш FilterDataList выглядит так же, как Except().ToList()..Where в вашем FilterList не использует p (аргумент лямбды), поэтому мне неясно, что вы хотите сделать с выражением фильтра.Возможно, вы ищете другой IEqualityComparer с Except(), который вы должны будете определить как отдельный класс.

1 голос
/ 10 февраля 2012

Если я правильно понимаю ваш вопрос, FilterList - это обобщенная версия FilterDataList, где вы передаёте лямбду в качестве параметра.В этом случае вы бы вызвали метод следующим образом:

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);
1 голос
/ 10 февраля 2012

Какой желаемый результат? Вы пробовали первый результат в https://www.google.com/search?q=linq+intersect? Похоже, вам следует ознакомиться с документацией Enumerable - вы используете. Все, что вы, скорее всего, имеете в виду. Любой, и в целом это даст вам лучшее представление о том, что возможно с LINQ.

...