帮助Except扩展方法的新覆盖

时间:2011-03-16 10:52:03

标签: c# linq

我想为IEnumerable编写一个新的Except扩展方法覆盖,它可以采用内联比较器而不是使用IEqualityComparer。

A,B是参考类型的集合..

这样的事情:

A: [1, A], [2, A], [3, A]

B: [3, B], [4, B], [5, B]

C = A.Except(B, (a,b) => a.Id == b.Id);

C: [1, A], [2, A]

我想知道你是否可以帮我解决这个方法的代码。

public static class IEnumerableExntesion
    {
        public IEnumerable<T> Except<T>(this IEnumerable<T> source, 
                                        IEnumerable<T> second, 
                                        Func<T, T, bool> predicate)
        {

        }
    }

我在考虑:

return source.Where (s => !second.Any(p => p.Id == s.Id));

但实际上我无法使用传递的谓词将其转换为通用解决方案!

任何帮助!

4 个答案:

答案 0 :(得分:2)

这应该有效:

return source.Where(s => !second.Any(p => predicate(s, p))

答案 1 :(得分:2)

return source.Where(s => !second.Any(p => predicate(p, s)));

答案 2 :(得分:2)

您是否需要使用谓词进行比较,还是可以使用投影来比较投影值?如果是这样,那么您可以使用某种ExceptBy方法:

var c = a.ExceptBy(b, x => x.Id);

var r = p.ExceptBy(q, x => x.Name, StringComparer.OrdinalIgnoreCase);

// ...

public static class EnumerableExtensions
{
    public static IEnumerable<TSource> ExceptBy<TSource, TKey>(
        this IEnumerable<TSource> first, IEnumerable<TSource> second,
        Func<TSource, TKey> keySelector,
        IEqualityComparer<TKey> keyComparer = null)
    {
        if (first == null) throw new ArgumentNullException("first");
        if (second == null) throw new ArgumentNullException("second");
        if (keySelector == null) throw new ArgumentNullException("keySelector");

        return first.ExceptByIterator(second, keySelector, keyComparer);
    }

    private static IEnumerable<TSource> ExceptByIterator<TSource, TKey>(
        this IEnumerable<TSource> first, IEnumerable<TSource> second,
        Func<TSource, TKey> keySelector, IEqualityComparer<TKey> keyComparer)
    {
        var keys = new HashSet<TKey>(second.Select(keySelector), keyComparer);

        foreach (TSource item in first)
        {
            if (keys.Add(keySelector(item)))
                yield return item;
        }
    }
}

答案 3 :(得分:0)

我会使用您传递的Func<T,T,bool>来创建通用IEqualityComparer并将其传递给常规Except

public class PredicateEqualityComparer<T> : IEqualityComparer<T>
{
    private readonly Func<T, T, bool> _predicate;

    public PredicateEqualityComparer(Func<T, T, bool> predicate)
    {
        _predicate = predicate;
    }

    public bool Equals(T x, T y)
    {
        return _predicate(x, y);
    }

    public int GetHashCode(T x)
    {
        return 0;
    }
}

您的扩展方法:

public static class IEnumerableExntesion
{
    public IEnumerable<T> Except<T>(this IEnumerable<T> source, 
                                    IEnumerable<T> second, 
                                    Func<T, T, bool> predicate)
    {
        return source.Except(second, new PredicateEqualityComparer(predicate));
    }
}    

请注意我有实施GetHashCode存根,最好正确实施它,但你必须为它传递另一个代理。