- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我正在尝试根据关键字过滤器来过滤推文。过滤器可以包含 10 个或更多单词。因此,如果一条推文包含关键字,它就会通过。我唯一能想到的就是将推文的文本拆分为标记。然后我会遍历过滤词并将每个标记与过滤器中的每个词进行比较。但是这种方式似乎很慢。假设关键词过滤器有N个关键词,token个数为M,则需要O(N*M)。
有没有更好的方法?
最佳答案
这个问题有很多有趣的方面和解决问题的方法。他们每个人都有权衡取舍。
当人们继续讨论 HashMap 和 O(1) 时,他们仍然缺少一些可以完成的编译时优化。了解编译时的单词集将使您能够将其放入 Enum
中,然后您可以使用鲜为人知的 EnumMap
( doc ) 和 枚举集
( doc )。枚举为您提供一个序数类型,然后您可以一次性调整支持数组或位域的大小,而不必担心扩展它。同样,枚举的散列是它的序数值,所以你没有复杂的散列查找(尤其是非中间字符串)。 EnumSet
是一种类型安全的位域。
import java.util.EnumSet;
public class Main {
public static void main(String[] args) {
EnumSet<Words> s = EnumSet.noneOf(Words.class);
for(String a : args) {
s.clear();
for(String w : a.split("\\s+")) {
try {
s.add(Words.valueOf(w.toUpperCase()));
} catch (IllegalArgumentException e) {
// nothing really
}
}
System.out.print(a);
if(s.size() == 4) { System.out.println(": All!"); }
else { System.out.println(": Only " + s.size()); }
}
}
enum Words {
STACK,
SOUP,
EXCHANGE,
OVERFLOW
}
}
在命令行上使用一些示例字符串运行时:
"stack exchange overflow soup foo""stack overflow""stack exchange blah"
One gets the results:
stack exchange overflow soup foo: All!stack overflow: Only 2stack exchange blah: Only 2
You've moved the what one matches to the core language, hoping its well optimized. Turns out this look like its ultimately just a Map<String,T>
(and digging even further its a HashMap hidden deep within the Class class.).
You've got a String. Splitting it into tokens of some sort is unavoidable. Each token needs to be examined to see if it matches. But comparing them against all the tokens is as you've noted expensive.
However, the language of "matches exactly these strings" is a regular one. This means we can use a regular expression to filter out the words that are not going to match. The regular expression runs in O(n)
time (see What is the complexity of regular expression? ).
This doesn't get rid of O(wordsInString * keyWords)
because that still is the worst case (which is what O() represents), but it does mean that for unmatched words you've only spent O(charsInWord)
on eliminating it.
package com.michaelt.so.keywords;
import java.util.EnumSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
final static Pattern pat = Pattern.compile("S(?:TACK|OUP)|EXCHANGE|OVERFLOW", Pattern.CASE_INSENSITIVE);
public static void main(String[] args) {
EnumSet<Words> s = EnumSet.noneOf(Words.class);
Matcher m = pat.matcher("");
for(String a : args) {
s.clear();
for(String w : a.split("\\s+")) {
m.reset(w);
if(m.matches()) {
try {
s.add(Words.valueOf(w.toUpperCase()));
} catch (IllegalArgumentException e) {
// nothing really
}
} else {
System.out.println("No need to look at " + w);
}
}
System.out.print(a);
if(s.size() == 4) { System.out.println(": All!"); }
else { System.out.println(": Only " + s.size()); }
System.out.println();
}
}
enum Words {
STACK,
SOUP,
EXCHANGE,
OVERFLOW
}
}
这给出了输出:
No need to look at foostack exchange overflow soup foo: All!stack overflow: Only 2No need to look at blahstack exchange blah: Only 2
现在,大失望了。尽管如此,对于 Java 来说,计算字符串的散列并在散列中查找它是否存在可能仍然更快。
这里唯一更好的方法是制作一个匹配所有字符串的正则表达式。如前所述,它是一种常规语言。
(?:stack\b.+?\bexchange\b.+?\bsoup\b.+?\boverflow)|(?:soup\b.+?\bexchange\b.+?\bstack\b.+?\boverflow) ...
上面的正则表达式将匹配字符串 stack exchange pea soup overflow
这里有四个字,就是4! (s1)|(s2)|(s3)|...(s24)
的部分 以这种方式处理的具有 10 个关键字的正则表达式将是 (s1)|...|(s3628800 )
这可能被认为是非常不切实际的。尽管某些引擎可能会在如此大的正则表达式上窒息,但这是可能的。尽管如此,它仍会将其缩减为 O(n),其中 n 是您所获得的字符串的长度。
请进一步注意,这是一个所有 过滤器,而不是一个任何 过滤器或一个一些 过滤器。
如果要匹配十个关键字中的一个,那么正则表达式只有十组长。如果你想匹配十个关键字中的 两个,那么它只有 90 个组长(有点长,但引擎可能不会阻塞它)。此正则表达式可以以编程方式生成。
这将使您回到 O(N) 时间,其中 N 是推文的长度。无需拆分。
关于java - 创建关键字过滤器的最快方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21207292/
如果我创建一个对象时没有使用 new 关键字,例如“Object s(someval)”,但该对象的构造函数使用了 new,当该对象超出范围时,是否会调用析构函数为其分配新的空间?我感觉好像是,但我不
在 SQL 语法中,我发现奇怪的规则表明 select * from ONLY (t1)是有效的 SQL。 我的问题是:什么是 ONLY在这种情况下是什么意思? 它在规范的“7.6 table ref
为什么使用 $(this) 而不是重新选择类很重要? 我在代码中使用了大量的动画和 CSS 编辑,并且我知道可以使用 $(this) 来简化它。 最佳答案 当您通过 jQuery 执行 DOM 查询(
我正在尝试使用 IN 关键字编写查询。 表A 属性标识、属性名称 表B key 、属性标识、属性值 根据提供的 key ,我想返回所有 attrName、attrVal 组合。结果将包含两个表中的列。
这个问题在这里已经有了答案: Why would you use "AS" when aliasing a SQL table? (8 个答案) 关闭 9 年前。 我不擅长写查询,但是从我开始使用
我读过,在 Java 中,您不必将 this 关键字显式绑定(bind)到对象,它由解释器完成。它与 Javascript 相反,在 Javascript 中你总是必须知道 this 的值。但是 Ja
Swift 中“with”关键字的用途是什么?到目前为止,我发现如果您需要覆盖现有的全局函数,例如 toDebugString,可以使用该关键字。 // without "with" you
这个问题在这里已经有了答案: What does the keyword "where" in a class declaration do? (7 个答案) 关闭 9 年前。 在下面的一段代码中(
免责声明:swift 菜鸟 您好,我刚刚开始学习 Swift,正在学习 Swift 编程语言(Apple 在 WWDC 期间发布的书籍),并且想知道“where”关键字是什么。它用于 let vege
深入研究文档后,我找不到以下问题的答案: 是否有任何理由反对使用 this 来引用当前对象,如下例所示? type MyStruct struct { someField string } fun
前言 最近在做THINKPHP开发项目中,用到了 parent:: 关键字,实际上 parent::关键字 是PHP中常要用到的一个功能,这不仅仅是在 THINKPHP 项目开发中,即使是一个小型
我们都知道且经常用到 unsigned 关键字,但有没有想过,与此对应的 signed 关键字有啥用? 复制代码 代码如下: int i = 0; signed
this关键字再java里面是一个我认为非常不好理解的概念,:)也许是太笨的原因 this 关键字的含义:可为以调用了其方法的那个对象生成相应的句柄。 怎么理解这段话呢? thinking i
一 什么是 synchronized synchronized 关键字提供了一种锁机制,能够确保共享变量互斥访问,从而防止数据不一致问题的出现。 synchronized 关键字包括 monitor
最近看了几篇 synchronized 关键字的相关文章,收获很大,想着总结一下该关键字的相关内容。 1、synchronized 的作用 原子性:所谓原子性就是指一个操作或者多个操作,要么全部执行并
在本教程中,您将借助示例了解 JavaScript 对象方法和 this 关键字。 在 JavaScript 中,对象也可以包含函数。例如, // object containing meth
有人可以解释一下 PHP“with”的作用吗? 示例开始: 假设我有一个类: \App\fa_batch 这句话有什么区别: $w = (with (new \App\fa_batch))
这个问题在这里已经有了答案: What is the difference between using the colon and as syntax for declaring type? (2
如果我在 WHERE 子句中使用以下任一项,是否会有很大不同: WHERE [Process Code] = 1 AND ([Material ID] = 'PLT' OR [Material ID]
This question is unlikely to help any future visitors; it is only relevant to a small geographic are
我是一名优秀的程序员,十分优秀!