我有一个包含 +-8000 个项目的列表,这是应用多种技术删除重复项后的结果(该列表最初包含 10000 多个项目)。
我现在有以下问题 -
示例 1. 杰克丹尼 2. 杰克丹尼 3. 杰克丹尼
显然,以上所有内容都与一个项目有关,但它们在技术上仍然是独一无二的。我尝试提取前 4 个字母并检查匹配项,但结果有 +-4000 个,其中大多数都是误报,即
- 杰克·德克斯
- 杰克·比克斯
两者都会拉杰克但不会成为有效的重复。
有什么想法吗?
答案1
根据 Zoredache 的评论,以下是我的示例工作簿使用 VBA 和编辑距离在大列表中查找相似的字符串。它基于@smirkingman 和@Apostolos55stackoverflow 上的答案。
两个单词之间的编辑距离是将一个单词更改为另一个单词所需的最少单字符编辑次数(插入、删除、替换)
我实现了两个不同的版本。请检查哪个函数对于 8000 个值的情况更快。如果您感兴趣,请查看完整的 VBA代码在Githubconst treshold = 1
。如果您希望结果中存在超过 1 个必需的编辑才能在某处获得匹配,请提高行中的阈值。
- 公式语法:
=LevenshteinCompare( <cell_to_check> , <range_to_search_in> )
示例:(=LevenshteinCompare(A2;A$2:A$12)
注意固定范围) - 输出语法:
<number_of_required_edits> - [<match_address>] <match_value>
Private Function Levenshtein(S1 As String, S2 As String)
Dim i As Integer, j As Integer
Dim l1 As Integer, l2 As Integer
Dim d() As Integer
Dim min1 As Integer, min2 As Integer
l1 = Len(S1)
l2 = Len(S2)
ReDim d(l1, l2)
For i = 0 To l1
d(i, 0) = i
Next
For j = 0 To l2
d(0, j) = j
Next
For i = 1 To l1
For j = 1 To l2
If Mid(S1, i, 1) = Mid(S2, j, 1) Then
d(i, j) = d(i - 1, j - 1)
Else
min1 = d(i - 1, j) + 1
min2 = d(i, j - 1) + 1
If min2 < min1 Then
min1 = min2
End If
min2 = d(i - 1, j - 1) + 1
If min2 < min1 Then
min1 = min2
End If
d(i, j) = min1
End If
Next
Next
Levenshtein = d(l1, l2)
End Function
Public Function LevenshteinCompare(S1 As Range, wordrange As Range)
Const treshold = 1
For Each S2 In Application.Intersect(wordrange, wordrange.Parent.UsedRange)
oldRes = newRes
newRes = Levenshtein(S1.Value, S2.Value)
If oldRes < newRes And oldRes <> "" Or S1.Address = S2.Address Then
newRes = oldRes
newS2row = oldS2row
Else
oldS2 = S2
oldS2row = S2.Address(0, 0)
End If
newS2 = oldS2
Next
If newRes <= treshold Then
LevenshteinCompare = newRes & " - [" & newS2row & "] " & newS2
Else
LevenshteinCompare = ""
End If
End Function
很有趣☜(゚ヮ゚☜)
答案2
使用 =len,如果差异小于 2,则标记为可能
并且像 =mid(Value,(len_Value - 7),4) 这样的值将其标记为可能的重复。
结合您已有的资源,您应该会得到一套更加可行的工作方案。
编辑
像这样的公式,请注意 G2 中的“Jack Daniel”<>“Jack Berries”。但看起来在其他地方都可能匹配。您需要进行一些修改以满足您的特定需求,但它应该达到一个可管理的数量。
C1 =IF(LEFT(A1,4)=LEFT(B1,4),"T","F")
D1 =IF(LEN(A1) - LEN(B1) <= 2,“T”,“F”)
E1 =LEN(A1)
F1 =LEN(B1)
G1 =IF(MID(A1,(E1 - 7),4) = MID(B1,(E1 - 7),4), "T","F")