给我一个包含90,000多个名字的列表.我要检查具有> = 50%相似性的名称,并将结果以以下格式写入文件:
ID 1,ID 2,相似度百分比.
我已经有一个检查相似性的算法,但是遍历整个列表需要花费很多时间.有人可以提供快速算法来比较名称吗?
下面是代码
public static void main(String[] args) throws IOException {
List list = new ArrayList<>();
int count = 0;
FileWriter f = new FileWriter(new File("output.txt"));
StringBuilder str = new StringBuilder();
Scanner scanner = new Scanner(new File("name.csv"));
while (scanner.hasNextLine()) {
count ;
list.add(scanner.nextLine());
}
long start = System.currentTimeMillis();
//
for (int i = 0; i < list.size(); i ) {
for (int j = i 1; j < list.size(); j ) {
int percent = StringSimilarity.simi(list.get(i), list.get(j));
if (percent >= 50) {
str.append("ID " i ",ID " j "," percent " percent");
str.append("\n");
}
}
}
long end = System.currentTimeMillis();
f.write(str.toString());
System.out.println((end - start) / 1000 " second(s)");
f.close();
scanner.close();
}
public static String getString(String s) {
Pattern pattern = Pattern.compile("[^a-z A-Z]");
Matcher matcher = pattern.matcher(s);
String number = matcher.replaceAll("");
return number;
}
这是数据外观的一个示例…..名称存储在中. csv文件,因此我读取了文件并将名称存储在列表中.
名,姓,其他名,母亲的名
金斯利,埃兹,本,西西
Eze,Daniel,Ben,Julie
乔恩·史密斯,凯莉,乔
约瑟夫·谭·切丽
约瑟夫·坦·杰斯·谢丽
….等等
一个人至少可以拥有3个名字…..就像我之前提到的,该程序是检查名字的相似度,因此在比较ID 1和ID 2时,“ ben”是常见的,“ eze”是常见的,因此它们有50%的相似度.
比较id 4和id 5,相似度为75%….因为即使id 4没有3名,它们也有3个相同的名字.
所以问题是…在使用两个for循环进行相似性检查期间,我从第一个id开始,并通过其余90,000个名称进行检查,并保存与之具有> = 50%相似性的id,然后进行下一个id 2并做同样的事情……依此类推
解决方法:
假定相似度函数是最佳的:如果11个字母中的6个不同,则只需简单地返回即可,例如0.
一种小改进是不使用StringBuilder并跳过已经找到的匹配项.这有点关键,因为它可能是A≈B∧B≈C∧A≉C,因此有些匹配项会丢失.
Charset charset = StandardCharsets.ISO_8859_1; // Better UTF_8
Path inputPath = Paths.get("names.txt");
List list = Files.readAllLines(inputPath, charset);
Path outputPath = Paths.get("output.txt");
try (PrintWriter out = new PrintWriter(Files.newBufferedWriter(path, charset))) {
int n = list.size();
for (int i = 0; i < n; i) {
list.set(i, normalize(list.get(i)));
}
for (int i = 0; i < n; i) {
String ithWord = list.get(i);
for (int j = i 1; j < n; j) {
String jthWord = list.get(j);
if (jthWord != null) {
int perc = similarity(ithWord, list.get(j));
if (similarity >= 50) {
out.printf("ID %d,ID %d,%d percent or greater%n", i, j, perc);
list.set(j, null); // Skip it for other i
}
}
}
}
}
可以使用Java 8的并行性:
final List list = ...
IntStream.range(0, list.size())
.parallelStream()
.map(i -> ...
...
但这不会改变二次复杂度.
这将有助于对列表进行排序,并从第ith个单词得出所有前缀均在90%范围内的前缀.不幸的是50%不可行(n超过n / 2).
我会要求其他要求,例如听起来相似,最多3个错字或类似的错字.或在晚上运行.来源:https://www.icode9.com/content-1-562051.html