【问题标题】:Elegant way to check if a String contains a keyword from a Set<String>检查字符串是否包含来自 Set<String> 的关键字的优雅方法
【发布时间】:2014-03-15 21:03:36
【问题描述】:

我有一个包含一些关键字的TreeSet&lt;String&gt;。我需要测试一些Strings 以查看它们是否包含这些关键字中的任何一个。

我目前有:

String tweet = object.getText();
for (String keyword : keywords_set)
{
    if(tweet.contains(keyword))
    {
        return true;
    }
}

对于字符串流,是否有更优雅、更有效的方法?

【问题讨论】:

  • @ZouZou 是的,他们是
  • 是的,我正在考虑另一种方法,用空格分割推文,然后为每个单词检查它是否在 Set 中(使用 HashSet),但这仍然是 O(n) 作为你的解决方案已经是。

标签: java string search treeset


【解决方案1】:

您不会比使用 JDK 类和方法更高效。您需要遍历Set 中的每个String 并检查您的String 是否包含它。

但是,如果您愿意使用第 3 方库 Guava,则可以使其更清洁。

使用 Guava,您可以使用 Iterables.any(Iterable, Predicate) which

如果 iterable 中的任何元素满足谓词,则返回 true。

像这样使用它

Set<String> keywords_set = ...
final String tweet = ...

return Iterables.any(keywords_set, new Predicate<String>() {
    @Override
    public boolean apply(String input) {
        return tweet.contains(input);
    }           
});

借助lambda expressionsaggregate operations,Java 8 将更加简洁。

【讨论】:

  • 对不起,完全错了。您提出的解决方案是 O(NLM),其中 N = 集合中的字符串数,L 是文本的长度,M 是集合中字符串的最大长度。您希望同时匹配所有字符串,以避免在集合大小中线性缩放(即上述界限中的 N 项)。这就是 Aho-Corasick 所做的。 (顺便说一句,我假设 String.contains() 使用类似 Boyer-Moore 的东西。)
  • @user3392484 我进行了编辑以指定这是您可以使用 JDK 类做的最好的事情。我将研究 Aho-Corasick 算法。
【解决方案2】:

【讨论】:

  • 你能再清楚一点吗?您将如何使用该算法?
  • 嗯,谷歌:en.wikipedia.org/wiki/… 链接到两个 Java 实现。用一个? (或者我在这里错过了什么?)
  • 不要把它放在 cmets 中,把它放在你的答案中。解释它如何实现更好的效率或性能或清洁度。
【解决方案3】:

这是一个关于如何使用 AhoCorasick 的明确示例。

I created a branch Robert Bor 的 java Aho-Corasick 实现添加了一个“matches”方法,一旦找到第一个匹配项就返回 true。

构建搜索树并非易事。我包含了一个与您提供的代码示例相匹配的低效方法实现。但是您确实想在大量搜索中分摊 trie 构造的成本。为此,您真的想更改调用您包含的示例的代码。

我提供了一个示例,说明如何构建一次搜索树,然后他们将其用于多次搜索。

public boolean doesTweetMatchSlow(String tweet, Set<String> keywords_set)
{
        Trie searchTrie = new Trie();
        for (String keyword : keywords_set) {
            searchTrie.addKeyword(keyword);
        }

        return searchTrie.matches(tweet);
}

public Collection<String> findMatchingTweetsFaster(Iterable<String> tweets, Set<String> keywords_set)
{
    List<String> matching = null;

    if (tweets != null) {
        matching = new ArrayList<>();

        if (keywords_set != null && !keywords_set.isEmpty()) {

            // build trie once.
            Trie searchTrie = new Trie();
            for (String keyword : keywords_set) {
                searchTrie.addKeyword(keyword);
            }

            for (String tweet : tweets) {
                // Re-use trie for every tweet.
                if (searchTrie.matches(tweet)) {
                    matching.add(tweet);
                }
            }
        }
    }
    return matching;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-31
    • 2021-03-05
    • 2013-03-14
    • 2011-03-19
    • 2010-09-26
    • 2015-11-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多