Ruby 标识包含列表中每个字符的字符串

Ruby 标识包含列表中每个字符的字符串,ruby,string,search,Ruby,String,Search,我有恐龙、剂量学和潮湿这几个词。我在想我有几十万个单词的情况。我想返回字符串中任意位置包含s、I、o、m的所有单词。功能应返回剂量测定,潮湿 有没有一种有效的方法可以做到这一点,或者我需要迭代和检查吗 A = ['o', 'i', 's', 'm'] words = ["dinosaur", "dosimetry", "moist", "personal", "since", "including", "guide", "shop", "directory", "board", "locat

我有恐龙、剂量学和潮湿这几个词。我在想我有几十万个单词的情况。我想返回字符串中任意位置包含s、I、o、m的所有单词。功能应返回剂量测定,潮湿

有没有一种有效的方法可以做到这一点,或者我需要迭代和检查吗

A = ['o', 'i', 's', 'm']
words = ["dinosaur", "dosimetry", "moist", "personal", "since",
  "including", "guide", "shop", "directory", "board", "location",
  "change", "white", "text", "small", "emotions", "rating",
  "rate", "movies", "government"]
这里有两个方法可以返回包含A中所有字母的单词

一,

手术路线可以改为

words.select { |word| (A-str.chars).empty? }
二,

这里有两个方法可以返回包含A中所有字母的单词

一,

手术路线可以改为

words.select { |word| (A-str.chars).empty? }
二,

只是为了经验

使用正则表达式正向前瞻

words = %w(dinosaur dosimetry moist)

words.select { |word| word.match?(/(?=.*m)(?=.*s)(?=.*i)(?=.*o).*/) }

#=> ["dosimetry", "moist"]
为了提高搜索速度,我根据。

将字母排列在正则表达式中只是为了体验一下

使用正则表达式正向前瞻

words = %w(dinosaur dosimetry moist)

words.select { |word| word.match?(/(?=.*m)(?=.*s)(?=.*i)(?=.*o).*/) }

#=> ["dosimetry", "moist"]

为了提高搜索速度,我按照.p>的要求在regex中排列字母,以更可读/永久的形式发布我的比较基准

require 'benchmark/ips'

words = %w(dinosaur dosimetry moist personal since including guide shop directory board
           location change white text small emotions rating rate movies government)
letters = %w[s i o m]
letters_freq = %w[m s i o]

# set up compiled greps
regexes = letters.map {|l| Regexp.compile(l) }

# set up search index
naive_search_index = words.each_with_object({}) do |word, memo|
  word.each_char do |c|
    memo[c] ||= []
    memo[c] << word
  end
end


# set up twiddle
n = 1
letter_flags = letters.each_with_object({}) do |c,h|
  h[c] = n
  n <<= 1
end
mask = n - 1


Benchmark.ips do |x|
  x.report('chained greps') do
    letters.reduce(words) do |result, letter|
      result.grep(Regexp.new(letter))
    end
  end

  x.report('compiled greps') do
    regexes.reduce(words) do |result, regex|
      result.grep(regex)
    end
  end

  x.report('include') do
    words.select do |word|
      letters.all?{|l| word.include?(l)}
    end
  end

  x.report('freq include') do
    words.select do |word|
      letters_freq.all?{|l| word.include?(l)}
    end
  end

  x.report("Cary") do
    words.select do |word|
      letters & word.chars == letters
    end
  end

  x.report('twiddle (cary 2)') do
    words.select do |word|
      n = 0
      word.each_char do |c|
        x = letter_flags[c]
        n |= x if x
      end
      n == mask
    end
  end

  x.report("mechnicov") do
    words.select do |word|
      word.match?(/(?=.*m)(?=.*s)(?=.*i)(?=.*o).*/)
    end
  end

  x.report('freq search index') do
    # most frequent first
    naive_search_index.values_at(*letters_freq).reduce(:&)
  end

  x.compare!
end

应要求,以更具可读性/永久性的形式发布我的比较基准

require 'benchmark/ips'

words = %w(dinosaur dosimetry moist personal since including guide shop directory board
           location change white text small emotions rating rate movies government)
letters = %w[s i o m]
letters_freq = %w[m s i o]

# set up compiled greps
regexes = letters.map {|l| Regexp.compile(l) }

# set up search index
naive_search_index = words.each_with_object({}) do |word, memo|
  word.each_char do |c|
    memo[c] ||= []
    memo[c] << word
  end
end


# set up twiddle
n = 1
letter_flags = letters.each_with_object({}) do |c,h|
  h[c] = n
  n <<= 1
end
mask = n - 1


Benchmark.ips do |x|
  x.report('chained greps') do
    letters.reduce(words) do |result, letter|
      result.grep(Regexp.new(letter))
    end
  end

  x.report('compiled greps') do
    regexes.reduce(words) do |result, regex|
      result.grep(regex)
    end
  end

  x.report('include') do
    words.select do |word|
      letters.all?{|l| word.include?(l)}
    end
  end

  x.report('freq include') do
    words.select do |word|
      letters_freq.all?{|l| word.include?(l)}
    end
  end

  x.report("Cary") do
    words.select do |word|
      letters & word.chars == letters
    end
  end

  x.report('twiddle (cary 2)') do
    words.select do |word|
      n = 0
      word.each_char do |c|
        x = letter_flags[c]
        n |= x if x
      end
      n == mask
    end
  end

  x.report("mechnicov") do
    words.select do |word|
      word.match?(/(?=.*m)(?=.*s)(?=.*i)(?=.*o).*/)
    end
  end

  x.report('freq search index') do
    # most frequent first
    naive_search_index.values_at(*letters_freq).reduce(:&)
  end

  x.compare!
end


如果需要经常执行这些查询,那么构建一些搜索索引可能是一个好主意。用一些RAM换取查询性能。@SergioTulentsev您所说的搜索索引是什么意思?它们不在数据库中。是的,一些手工制作的数据结构便于搜索。例如,这里是所有包含字母“a”的单词,这里是所有包含字母“b”的单词。或者类似的东西。我所说的例子。这个指数非常幼稚,肯定可以显著提高:@SergioTulentsev我明白了。谢谢你的例子!如果需要经常执行这些查询,那么构建一些搜索索引可能是一个好主意。用一些RAM换取查询性能。@SergioTulentsev您所说的搜索索引是什么意思?它们不在数据库中。是的,一些手工制作的数据结构便于搜索。例如,这里是所有包含字母“a”的单词,这里是所有包含字母“b”的单词。或者类似的东西。我所说的例子。这个指数非常幼稚,肯定可以显著提高:@SergioTulentsev我明白了。谢谢你的例子!这比A.all{A | str.include?A}@Sergio慢2.5倍,这很有趣,我想也不奇怪。一个人,所有人?遇到错误时短路。在你所有的基准中?尝试使用A=['m','s','i','o'],基于。@Sergio,直到我完成了这个基准测试,我才看到您的上级基准测试链接在一个评论呻吟中。你应该发布它,可能包括我上面提到的一些其他方法。如果您这样做,我将很高兴地将我的答案回滚到添加基准之前的答案。如果您坚持…:这比A.all{A | str.include?A}@Sergio慢2.5倍,这很有趣,我想也不奇怪。一个人,所有人?遇到错误时短路。在你所有的基准中?尝试使用A=['m','s','i','o'],基于。@Sergio,直到我完成了这个基准测试,我才看到您的上级基准测试链接在一个评论呻吟中。你应该发布它,可能包括我上面提到的一些其他方法。如果您这样做,我将很高兴地将我的答案回滚到添加基准之前的答案。如果您坚持…:尽管看起来很吓人,但这是我测试过的最快的。Maaaybe当我们必须动态地构建这个正则表达式时,一些速度将会消失。哈哈哈。竞争谁更快。现在,我来领导。但是说真的,当有成百上千的单词时,重要的是这个问题包含了“有效”这个词。我很无聊。所以我在进行基准测试:我很惊讶,但是。*提高了我不敢相信的速度。*有帮助,所以我自己重新运行@Sergio的基准测试,有没有。*。果然,我也得到了同样的结果。我想知道它为什么有用。读者:有什么想法吗?尽管看起来很吓人,但这是我测试过的最快的。Maaaybe当我们必须动态地构建这个正则表达式时,一些速度将会消失。哈哈哈。竞争谁更快。现在,我来领导。但是说真的,当有成百上千的单词时,重要的是这个问题包含了“有效”这个词。我很无聊。所以我在进行基准测试:我很惊讶,但是。*提高了我不敢相信的速度。*有帮助,所以我自己重新运行@Sergio的基准测试,有没有。*。果然,我也得到了同样的结果。我想知道它为什么有用。读者:有什么想法吗?如果我们使用字母和朴素的搜索索引,我们将赢得另外12%。干得好!请注意,@mechnicov已将其正则表达式更新为/?=.*s?=.*i?=.*o?=.*m./.*在最后没有效果,但他报告说,这提高了性能,我觉得奇怪。顺便说一句,如果你想避免垂直滚动的需要,插入一些行。最重要的是避免干扰代码的剪切和粘贴
重新运行基准测试,直到我的解决方案不是最后一个?@CarySwoveland我尝试过,但它不会改变。这就好像基准反映了现实或其他什么。奇怪@塞吉奥,我已经根据字母频率修改了正则表达式。速度加快了。你可以修改你的基准。如果我们使用字母_freq和朴素的搜索索引,我们将赢得另外12%。干得好!请注意,@mechnicov已将其正则表达式更新为/?=.*s?=.*i?=.*o?=.*m./.*在最后没有效果,但他报告说,这提高了性能,我觉得奇怪。顺便说一句,如果你想避免垂直滚动的需要,插入一些行。最重要的是避免干扰剪切和粘贴代码。一个小请求:你能重新运行基准测试,直到我的解决方案不是最后一个吗?@CarySwoveland我试过了,但它不会改变。这就好像基准反映了现实或其他什么。奇怪@塞吉奥,我已经根据字母频率修改了正则表达式。速度加快了。您可以对基准进行更改。