我需要有效地找到字符串列表对的比例(交叉点大小/联合大小)。列表很小(大多数是3到10个项目),但我有很多(~300K)并且必须在每对上执行此操作,因此我需要这个实际计算尽可能高效。字符串本身是短的unicode字符串 - 平均大约5-10个unicode字符。
这里接受的答案Efficiently compute Intersection of two Sets in Java?看起来非常有帮助但是(可能因为我的设置很小(?))我没有通过使用接受答案中建议的方法得到很多改进。
这是我到目前为止所拥有的:
protected double uuEdgeWeight(UVertex u1, UVertex u2) {
Set<String> u1Tokens = new HashSet<String>(u1.getTokenlist());
List<String> u2Tokens = u2.getTokenlist();
int intersection = 0;
int union = u1Tokens.size();
for (String s:u2Tokens) {
if (u1Tokens.contains(s)) {
intersection++;
} else {
union++;
}
}
return ((double) intersection / union);
我的问题是,我是否可以采取任何措施来改善这一点,因为我正在使用String
来检查相等性比其他数据类型更耗时。
我认为因为我将多个u2与同一个u1进行比较,我可以通过将u2克隆到循环外的HashSet(未显示)来获得一些改进 - 这意味着我会传入HashSet而不是我可以从中拉出列表然后克隆到集合中的对象
我能做些什么来呐喊甚至是一个小改进吗?
提前致谢!
更新
我已更新上述问题的数字细节。此外,由于数据的性质,大多数(90%?)的交叉点将是空的。我最初的尝试使用了克隆集合,然后retainAll
另一组方法中的项目来查找交集,然后在执行克隆之前快捷方式,并addAll
找到联合。这与上面发布的代码一样高效,大概是因为它之间的交易是一个较慢的算法整体而不是能够在很多时候缩短。所以,我正在考虑如何利用重叠集的频率,并对这方面的任何建议表示赞赏。
提前致谢!
答案 0 :(得分:1)
通过在循环外部移动HashSet可以获得很大的改进。
如果HashSet确实只有一些条目,那么你实际上可能同样快地使用一个数组 - 因为遍历一个数组要简单得多/更快。我不确定阈值在哪里,但我会测量两者 - 并确保你正确地进行测量。 (即在定时循环之前预热循环等)。
要尝试的一件事可能是使用排序数组来进行比较。扫描直到您超过当前状态,您可以立即中止搜索。这将改善处理器分支预测并稍微减少比较次数。
答案 1 :(得分:0)
如果你想优化这个函数(不确定它是否真的在你的上下文中工作),你可以为每个唯一的String赋予一个Int值,当String被添加到Intert作为BitSet中的位的UVertex集时。
此函数应该成为set.or(otherset)和set.and(otherset)。取决于可能有效的唯一字符串的数量。