找出大型列表中的哪些单词出现在一个小字符串中

我有一个静态的“大”单词列表,大约300-500个单词,名为’list1′

给出一个约40字的相对较短的字符串str ,ruby中最快的方法是:

  1. list1的单词出现在str (计算多次出现次数)
  2. list1中的哪些单词在字符串str中出现一次或多次的列表
  3. (2)中的单词数

str ‘Occuring’既可以表示str中的整个单词,也可以表示str单词中的部分单词。 因此,如果'fred'list1并且str包含'fred''freddie' ,那将是两个匹配。

一切都是小写的,所以任何匹配都不必关心案例。

例如:

 list1 ="fred sam sandy jack sue bill" str = "and so sammy went with jack to see fred and freddie" 

所以str包含samjackfred (两次)

对于第(1)部分,表达式将返回4(sam + jack + fred + fred)
对于第(2)部分,表达式将返回“sam jack fred”
第(3)部分是3

这样做的“ruby方式”在4小时之后就消失了……迭代它很容易(但很慢)。 任何帮助,将不胜感激!

这是我的镜头:

 def match_freq(exprs, strings) rs, ss, f = exprs.split.map{|x|Regexp.new(x)}, strings.split, {} rs.each{|r| ss.each{|s| f[r] = f[r] ? f[r]+1 : 1 if s=~r}} [f.values.inject(0){|a,x|a+x}, f, f.size] end list1 = "fred sam sandy jack sue bill" str = "and so sammy went with jack to see fred and freddie" x = match_freq(list1, str) x # => [4, {/sam/=>1, /fred/=>2, /jack/=>1}, 3] 

“match_freq”的输出是输出项(a,b,c)的数组。 算法本身是O(n*m) ,其中n是list1中的项目数, m是输入字符串的大小,我认为你不能做得更好(就大哦而言)。 但是有一些较小的优化可能会得到回报,比如为匹配总数保留一个单独的计数器而不是之后计算它。 这只是我对它的快速破解。

您可以从输出中仅提取匹配的单词,如下所示:

 matches = x[1].keys.map{|x|x.source}.join(" ") # => "sam fred jack" 

请注意,订单不会被保留,如果重要的话,您必须保留单独的订单列表。

这是一个替代实现,用于您的启发:

 def match_freq( words, str ) words = words.split(/\s+/) counts = Hash[ words.map{ |w| [w,str.scan(w).length] } ] counts.delete_if{ |word,ct| ct==0 } occurring_words = counts.keys [ counts.values.inject(0){ |sum,ct| sum+ct }, # Sum of counts occurring_words, occurring_words.length ] end list1 = "fred sam sandy jack sue bill" str = "and so sammy went with jack to see fred and freddie" x = match_freq(list1, str) px #=> [4, ["fred", "sam", "jack"], 3] 

请注意,如果我需要这些数据,我可能只是从方法中返回’counts’哈希值,然后对它进行任何我想要的分析。 如果我要从分析方法返回多个“值”,我可能会返回一个命名值的哈希值。 虽然,返回一个数组允许你取消结果:

 hits, words, word_count = match_freq(list1, str) p hits, words, word_count #=> 4 #=> ["fred", "sam", "jack"] #=> 3 

要获得更快的正则表达式 ,请使用https://github.com/mudge/re2 。 它是Google re2的ruby包装https://code.google.com/p/re2/