3

我正在使用以下查询来检测数据库中的重复项。

使用 LINQ 连接效果不佳,因为 X 公司也可能被列为 X 公司,因此我想修改它以检测“接近重复”。

var results = result
                .GroupBy(c => new {c.CompanyName})
                .Select(g => new CompanyGridViewModel
                    {
                        LeadId = g.First().LeadId,
                        Qty = g.Count(),
                        CompanyName = g.Key.CompanyName,
                    }).ToList();

有人可以建议一种我可以更好地控制比较的方法吗?也许通过 IEqualityComparer (虽然我不完全确定在这种情况下会如何工作)

我的主要目标是:

  1. 列出包含所有重复项(或“接近重复项”)子集的第一条记录
  2. 为了对我用于重复项的字段和文本比较具有一定的灵活性。
4

3 回答 3

1

好的,既然你正在寻找不同的排列,你可以这样做:

请记住,这是写在答案中的,因此它可能无法完全编译,但您明白了。

var results = result
    .Where(g => CompanyNamePermutations(g.Key.CompanyName).Contains(g.Key.CompanyName))
    .GroupBy(c => new {c.CompanyName})
    .Select(g => new CompanyGridViewModel
        {
            LeadId = g.First().LeadId,
            Qty = g.Count(),
            CompanyName = g.Key.CompanyName,
        }).ToList();

private static List<string> CompanyNamePermutations(string companyName)
{
    // build your permutations here
    // so to build the one in your example
    return new List<string>
    {
        companyName,
        string.Join("", companyName.Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
    };
}
于 2012-11-05T12:23:41.660 回答
1

对于您明确的“忽略空格”情况,您可以简单地调用

var results = result.GroupBy(c => c.Name.Replace(" ", ""))...

但是,在您需要灵活性的一般情况下,我会建立一个类库IEqualityComparer<Company>以在您的分组中使用。例如,这应该在您的“忽略空间”情况下做同样的事情:

public class CompanyNameIgnoringSpaces : IEqualityComparer<Company>
{
    public bool Equals(Company x, Company y)
    {
        return x.Name.Replace(" ", "") == y.Name.Replace(" ", "");
    }

    public int GetHashCode(Company obj)
    {
        return obj.Name.Replace(" ", "").GetHashCode();
    }
}

您可以将其用作

var results = result.GroupBy(c => c, new CompanyNameIgnoringSpaces())...

做包含多个字段或其他相似性定义等的类似事情非常简单。

请注意,您对“相似”的定义必须是可传递的,例如,如果您正在查看整数,则不能将“相似”定义为“在 5 以内”,因为那样您就会有“0 与 5 相似”和“ 5 类似于 10”,但不是“0 类似于 10”。(它也必须是自反和对称的,但这更直接。)

于 2012-11-05T12:28:17.680 回答
1

在这种情况下,您需要定义工作将发生的位置,即完全在服务器上、在本地内存中或两者的混合。

  1. 在本地内存中:在这种情况下,我们有两条路线,将所有数据拉回并在本地内存中执行逻辑,或者将数据流式传输并分段应用逻辑。仅拉取所有数据ToList()ToArray()基表。要流式传输数据,建议使用ToLookup()自定义 IEqualityComparer,例如

    public class CustomEqualityComparer: IEqualityComparer<String>
    {
        public bool Equals(String str1, String str2)
        {
            //custom logic
        }
    
        public int GetHashCode(String str)
        {
            // custom logic
        }
    }
    
    //result
    var results = result.ToLookup(r => r.Name, 
                        new CustomEqualityComparer())
                        .Select(r => ....)
    
  2. 完全在服务器上:取决于您的提供商以及它可以成功映射的内容。例如,如果我们将近似重复定义为具有替代分隔符的重复,则可以执行以下操作:

    private char[] delimiters = new char[]{' ','-','*'}
    
    var results = result.GroupBy(r => delimiters.Aggregate( d => r.Replace(d,'')...
    
  3. 混合:在这种情况下,我们将两者之间的工作分开。除非你想出一个好的方案,否则这条路线很可能效率低下。例如,如果我们将逻辑保留在本地,将分组构建为从名称到键的映射,然后查询生成的分组,我们可以执行以下操作:

    var groupings = result.Select(r => r.Name)
                          //pull into local memory
                          .ToArray()
                          //do local grouping logic...
    
                          //Query results
    var results = result.GroupBy(r => groupings[r]).....
    

就我个人而言,我通常选择第一个选项,为小数据集拉取所有数据并流式传输大数据集(根据经验,我发现每次拉取之间的逻辑流式传输比拉取所有数据然后执行所有逻辑要长得多)

注意:依赖于提供者ToLookup()通常是立即执行并且在构造中分段应用它的逻辑。

于 2012-11-05T13:25:29.993 回答