我有一个静态的'大'单词列表,大约300-500个单词,名为'list1'
给出一个约40个单词的相对较短的字符串str
,这是ruby中最快的方法:
list1
中str
中的单词出现的次数(计算多次出现次数)list1
中的单词在字符串str 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
包含sam
,jack
,fred
(两次)
对于部分(1),表达式将返回4(sam + jack + fred + fred)
对于第(2)部分,表达式将返回“sam jack fred”
第(3)部分是3
执行此操作的'红宝石方式'在4小时后躲过我...迭代它很容易(但很慢)。任何帮助将不胜感激!
答案 0 :(得分:2)
以下是我拍摄的照片:
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"
请注意,订单不会被保留,如果重要的话,您必须保留单独的订单列表。
答案 1 :(得分:2)
这是一个替代实现,用于您的启发:
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)
p x #=> [4, ["fred", "sam", "jack"], 3]
请注意,如果我需要这些数据,我可能只是从方法中返回'counts'哈希值,然后根据需要进行任何分析。如果我要从分析方法返回多个'值',我可能会返回一个命名值的哈希值。虽然,返回一个数组允许你取消结果:
hits, words, word_count = match_freq(list1, str)
p hits, words, word_count
#=> 4
#=> ["fred", "sam", "jack"]
#=> 3
答案 2 :(得分:0)
对于更快的正则表达式,请使用https://github.com/mudge/re2。它是 Google re2 https://code.google.com/p/re2/
的红宝石包装