按单词匹配搜索重复项



我在列表中有这样的数据:

Microsoft Ltd
Microsoft
Google Inc
Amazon Ltd.
Amazon Ltd.
DropBox Corporation Ltd.
DropBox Corporation

我目前的解决方案能够检测到完全匹配的重复项。因此,它当前将输出:

Amazon Ltd.
Amazon Ltd.

我想添加一种可能性,这样这些也会出现在输出列表中:

Microsoft Ltd
Microsoft
Amazon Ltd.
Amazon Ltd.
DropBox Corporation Ltd.
DropBox Corporation

这是我当前的代码:

var dups = companyList.AsEnumerable()
.Where(g => !string.IsNullOrWhiteSpace(g.Name))
.GroupBy(dr => dr.Name.Trim())
.Where(gr => gr.Count() > 1)
.SelectMany(g => g)
.OrderBy(c => c.Name)
.ToList();

我将非常感谢任何善意的建议,这将导致实现这样一个检查的解决方案?我个人认为这里没有任何可能的逻辑解决方案?也许只有某种基于分数的Levenstein距离计算和检测?如果无论如何都不可能,那么至少获得这些(通过多个单词匹配,例如两个(将是有益的:

DropBox Corporation Ltd.
DropBox Corporation

您可以编写自己的相等比较器,定义何时将两个公司名称作为同一公司。它需要实现两种方法:

  • GetHashCode()哪种类型的隔离将对哪些公司进行比较-它们需要具有相同的哈希代码值。在您的情况下,我认为没有比为所有值硬编码以便相互比较更好的选择了
  • Equals(),它通过检查名称来说明是否两个公司实际上被视为同一家。你可以随心所欲地调整它,你会发现它正在你的测试集上发挥作用(我想有些实验是必要的(

下面你可以找到我的实现,当我假设公司如果相差一个单词最大值,就会被视为相同的。

public class Program
{
public static void Main()
{
var companyNames = new[]
{
"Microsoft Ltd",
"Microsoft",
"Google Inc",
"Google Drive Inc",
"Amazon Ltd.",
"Amazon Ltd.",
"DropBox Corporation Ltd.",
"DropBox Corporation",
"Corporation DropBox"
};
var companies = companyNames.Select(cn => new Company {Name = cn});
var groups = companies
.GroupBy(c => c, new CompanyComparer())
.Where(gr => gr.Count() > 1);
PrintResults(groups);
Console.ReadKey();
}

private static void PrintResults(IEnumerable<IGrouping<Company, Company>> groups)
{
foreach (var grp in groups)
{
foreach (var c in grp)
{
Console.WriteLine(c.Name);
}
Console.WriteLine();
}
}
}
public class Company
{
public string Name { get; set; }
}
public class CompanyComparer : IEqualityComparer<Company>
{
public bool Equals(Company x, Company y)
{
if (x?.Name == null || y?.Name == null) return false;
var xWords = GetWordsSet(x.Name);
var yWords = GetWordsSet(y.Name);
// make company with more words first
if (xWords.Count < yWords.Count)
{
var temp = xWords;
xWords = yWords;
yWords = temp;
}
var commonWords = xWords.Count(xWord => yWords.Contains(xWord));
return xWords.Count - commonWords <= 1;
}
public int GetHashCode(Company obj) => 0; // only companies with same hash code will be compared
private static ISet<string> GetWordsSet(string name) =>
name.Split().Select(n => n.ToLower()).ToHashSet();
}

哪个输出:

Microsoft Ltd
Microsoft
Google Inc
Google Drive Inc
Amazon Ltd.
Amazon Ltd.
DropBox Corporation Ltd.
DropBox Corporation
Corporation DropBox

您可以通过删除标点符号和诸如"Inc公司"Corp";(见下面的部分例子(,并通过删除括号,但最终这是一个非常困难的问题,因为(i(缩写;(ii(位置说明(东部、北部……(;(iii(公司分类:它是子公司、分公司、特许经营商还是单独的公司?

最终,同义词列表可能是最好的方法,再加上一些简单的规范化,可以删除常见的公司实体类型指示符。

private static string Clean(string corporation)
{
corporation = corporation.EndsWith("Inc") ? corporation.Substring(0, corporation.Length - 3) : corporation;
return corporation
.Replace(" LLC", "")
.Replace(" S.A.", "")
.Replace(" SA", "")
.Replace(" S.L.", "")
.Replace(" SL", "")
.Replace("(1)", "")
.Replace(" GmbH", "")
.Replace("(UK) Ltd.", "")
.Replace(" Limited", "")
.Replace(" Corporation", "")
.Replace(" Corp.", "")
.Replace(" Corp ", " ")
.Replace(" Ltd.", "")
.Replace(" Ltd", "")
.Replace(" Inc.", "")
.Replace("(Pa)", "")
.Replace(" Inc ", " ")
.Replace(" Corporation", "")
.Replace(", LLP.", "")
.Replace(" N.V.", "").Trim();
}

最新更新