【问题标题】:Efficient Intersection and Union of Lists of Strings字符串列表的高效交集和并集
【发布时间】:2014-01-06 19:05:18
【问题描述】:

我需要有效地找到字符串列表对的(交集大小/联合大小)的比率。这些列表很小(主要是大约 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);

我的问题是,鉴于我正在使用 Strings,与其他数据类型相比,检查相等性可能更耗时。

我认为因为我将多个 u2 与同一个 u1 进行比较,所以我可以通过将 u2 克隆到循环外的 HashSet 中来获得一些改进(这没有显示——这意味着我会传入HashSet 而不是我可以从中提取列表然后克隆到集合中的对象)

我还能做些什么来稍微改进一下?

提前致谢!

更新

我已经更新了上述问题的具体数字。此外,由于数据的性质,大多数(90%?)的交叉点将是空的。我最初尝试使用克隆集合,然后使用retainAll 另一个集合方法中的项目来查找交集,然后在进行克隆和addAll 之前使用快捷方式找到并集。这与上面发布的代码一样有效,大概是因为它是一个整体上较慢的算法与能够缩短很多时间之间的权衡。因此,我正在考虑如何利用重叠集的不频繁性,并希望在这方面提出任何建议。

提前致谢!

【问题讨论】:

  • 这个问题似乎离题了,因为它是关于代码审查的,属于 codereview.stackexchange.com 不在这里。
  • 您的列表是否有可能包含任何重复项?我也认为这不是一个代码审查,而是一个关于如何找到字符串集的快速交集和并集的有趣算法问题。
  • 我想反驳的论点是这是行不通的,因为它不够快。这里和代码审查之间有一些重叠,因为他对这段代码有一个具体的问题,我认为没关系。
  • 我看到这篇文章已被搁置为“离题”。如果我对其进行编辑以排除代码 sn-p 并仅询问有关如何在 Java 中最有效地执行此操作的一般性问题,是否会成为主题?我有点困惑,因为社区标准页面指出好的问题通常应该包含一些代码。他们没有说它必须是损坏的代码。我发布的代码计算了正确的函数,但它的效率不足以让我使用它,所以正如@TimB 所说,它对我的​​目的来说不是“工作”。
  • @JarrodRoberson 仅仅因为一个问题在其他地方是热门话题并不意味着它在这里是题外话。特别是,仅仅因为一个问题询问如何改进工作代码并不意味着它在 StackOverflow 上是题外话。请参阅 this Meta thread 关于该场景的详细信息。

标签: java optimization set performance


【解决方案1】:

通过将 HashSet 移到循环之外,您将获得很大的改进。

如果 HashSet 中确实只有几个条目,那么您实际上可能与使用数组一样快 - 因为遍历数组更简单/更快。我不确定阈值在哪里,但我会测量两者 - 并确保你正确地进行测量。 (即在定时循环之前预热循环等)。

要尝试的一件事可能是使用排序数组来比较事物。扫描直到超过当前,您可以立即中止搜索。这将改善处理器分支预测并减少比较次数。

【讨论】:

  • 谢谢!我会尝试将它保存在数组中,看看那里会发生什么。通过将 HashSet 移到循环之外(在我的数据集的基准部分上运行大约需要 15 分钟),我(令人惊讶地)没有获得明显的收益。我希望通过这样做我能获得相当大的胜利。 :-/ 我不确定如何正确地进行热身循环等测量。我会查一下。除了在我的一大块数据上运行我的代码并比较它需要多长时间之外,我什么都没做。
  • 这是我不久前在基准测试中写的(非常简短的)答案stackoverflow.com/questions/20655963/…
  • 对数组思路进行了改进。
【解决方案2】:

如果你想优化这个函数(不确定它是否真的在你的上下文中工作)你可以为每个唯一的 String 分配一个 Int 值,当 String 添加到 UVertex 集时,该 Int 作为 BitSet 中的一个位。

这个函数应该变成一个 set.or(otherset) 和一个 set.and(otherset)。取决于可能有​​效的唯一字符串的数量。

【讨论】:

  • 可能会有大约一百万个唯一字符串。这仍然是一个合理的尝试选择吗?要分配唯一的整数,将所有字符串放入某种哈希并使用哈希值是否有意义?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-25
  • 2015-06-02
相关资源
最近更新 更多