获取所有可能的子串和它们的数量

时间:2018-01-11 14:21:55

标签: ruby substring

我正在尝试将所有可能的子串和它们的计数放入哈希中。 例如。

 "abc" => { a: 1, b: 1, ab: 1, bc: 1}

为此,我编写了以下代码:

 def get_all(b)
     (0..(b.size-1)).to_a.combination(2).inject({}) { |h, g|
        s = b[g[0],g[1]]
        h[s] ? ( h[s] += 1) : ( h[s] = 1 )
        h 
      } 
 end

但不知怎的,它无法正常工作,因为"abchh"它返回:

{"a"=>1, "ab"=>1, "abc"=>1, "abch"=>1, "bc"=>1, "bch"=>1, "bchh"=>1, "chh"=>2, "hh"=>1}

chh在那里两次,但我无法理解为什么。我错了什么?

谢谢!

1 个答案:

答案 0 :(得分:2)

可以通过各种方式调用

String#[],包括:

str[start, length] → new_str or nil
str[range]         → new_str or nil

前者需要 start length ,而后者需要一个表示 start end 的范围。< / p>

因此,而不是两个参数g[0]g[1]

b[g[0], g[1]]

你必须传递一个参数g[0]..g[1]

b[g[0]..g[1]]

此外,您还必须使用repeated_combination来获取单个字符:

(0..2).to_a.combination(2).to_a
#=> [[0, 1], [0, 2], [1, 2]]

(0..2).to_a.repeated_combination(2).to_a
#=> [[0, 0], [0, 1], [0, 2], [1, 1], [1, 2], [2, 2]]

此外,您的代码可以简化:

  • 使用a...b代替a..(b-1)
  • 更喜欢each_with_object而不是inject,因此您无需从块中返回哈希
  • 通过Hash.new(0)
  • 设置默认哈希值
  • 通过(i, j)将元组数组分解为i..j而不是g[0]..g[1]

示例:( indices变量可以内联)

def get_all(str)
  indices = (0...str.size).to_a.repeated_combination(2)
  indices.each_with_object(Hash.new(0)) do |(i, j), h|
    h[str[i..j]] += 1
  end
end

或者,使用两个嵌套循环:

def get_all(str)
  (0...str.size).each_with_object(Hash.new(0)) do |i, h|
    (i...str.size).each do |j|
      h[str[i..j]] += 1
    end
  end
end

也许这种方法已经做得太多了。我可能会把它分成两个方法:一个用于枚举子串,另一个用于计算它们。