【问题标题】:Duplicate by using LINQ with mulitiple OR creteria使用具有多个 OR 条件的 LINQ 进行复制
【发布时间】:2024-05-04 01:35:04
【问题描述】:

我可以使用此查询检索重复项:

var duplicates = grpDupes
    .GroupBy(i => new { i.Email })
    .Where(g => g.Count() > 1)
    .SelectMany(g => g);

但我有兴趣通过使用 EmailAddress 或 xyz 来查找重复项。 如果我修改上面的查询

GroupBy(i => new { i.Email, i.Address }) 

然后它变成 AND 条件,有什么帮助吗?

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    您必须使用接受EqualityComparer 的重载方法。

        /// <summary>
    /// Factory class which creates an EqualityComparer based on lambda expressions.
    /// </summary>
    /// <typeparam name="T">The type of which a new equality comparer is to be created.</typeparam>
    public static class EqualityComparerFactory<T>
    {
        private class MyComparer : IEqualityComparer<T>
        {
            private readonly Func<T, int> _getHashCodeFunc;
            private readonly Func<T, T, bool> _equalsFunc;
    
            public MyComparer(Func<T, T, bool> equalsFunc, Func<T, int> getHashCodeFunc = null)
            {
                _getHashCodeFunc = getHashCodeFunc ?? (a=>0);
                _equalsFunc = equalsFunc;
            }
    
            public bool Equals(T x, T y)
            {
                return _equalsFunc(x, y);
            }
    
            public int GetHashCode(T obj)
            {
                return _getHashCodeFunc(obj);
            }
        }
    
        /// <summary>
        /// Creates an <see cref="IEqualityComparer{T}" /> based on an equality function and optionally on a hash function.
        /// </summary>
        /// <param name="equalsFunc">The equality function.</param>
        /// <param name="getHashCodeFunc">The hash function.</param>
        /// <returns>
        /// A typed Equality Comparer.
        /// </returns>
        public static IEqualityComparer<T> CreateComparer(Func<T, T, bool> equalsFunc, Func<T, int> getHashCodeFunc = null)
        {
            ArgumentValidator.NotNull(() => equalsFunc);
    
            return new MyComparer(equalsFunc, getHashCodeFunc);
        }
    }
    

    示例用法:

            var comparer = EqualityComparerFactory<YourClassHere>.CreateComparer((a, b) => a.Address == b.Address || a.Email == b.Email);
    
            data.GroupBy(a => a, comparer);
    

    【讨论】:

    • 没有哈希码方法会抛出ArgumentNullException 不是吗?
    • 是的,抱歉,我选择了更新的版本。坚持,稍等。 ...完成
    • 对这个问题的回答有点违反YAGNI
    • 谢谢 有两个问题,ArgumentValidator 在当前上下文中不存在不带 2 个参数 var comparer = EqualityComparerFactory.CreateComparer(null, (a, b) => a.Address == b.地址 || a.Email == b.Email );
    • 对不起那个。这个来自我正在使用的框架。
      到第二个问题:只需省略 null 参数。
    【解决方案2】:

    您可以在 SQL 中使用 EXISTS,在 LINQ 中使用 Any

    var duplicates = grpDupes
        .Where(i => (i.Email.Trim() != "" || i.Address.Trim() != "")  && grpDupes
            .Any(i2 => i.ID != i2.ID && 
                ((i.Email.Trim()   != "" && i.Email   == i2.Email) || 
                 (i.Address.Trim() != "" && i.Address == i2.Address))));
    

    请注意,我使用 ID 作为主键列。如果没有,则需要使用要用作标识符的列。

    如果您使用数据库驱动的 LINQ 提供程序,如 LINQ-To-SQL 或 LINQ-To-Entities,这是有效的。

    【讨论】:

    • 这似乎有效,有人告诉我为什么我不应该使用它吗?
    • 我们能否通过忽略 i.Email 中的空白电子邮件或地址来改善这一点 == i2.Email || i. 地址 == i2. 地址)。如果两个记录中的电子邮件都为空,那么它也认为它是重复的
    • @user3636316:我已经编辑了我的答案,以提供一种适用于所有 LINQ 提供程序的方法(例如,与 String.IsNullOrWhiteSpace 相反)。
    【解决方案3】:

    我会使用.ToLookup() 保持这个非常简单。

    这个怎么样?

    var emailLookup = grpDupes.ToLookup(x => x.Email);
    var addressLookup = grpDupes.ToLookup(x => x.Address);
    
    var duplicates = grpDupes
        .Where(x =>
            emailLookup[x.Email].Count() > 1 || addressLookup[x.Address].Count() > 1);
    

    【讨论】:

      最近更新 更多