【问题标题】:Show all substring replacement options in Ruby [duplicate]显示 Ruby 中的所有子字符串替换选项 [重复]
【发布时间】:2014-03-01 16:17:12
【问题描述】:

我正在尝试显示子字符串替换的所有可能选项。例如,如果我有这个字符串:

my_string = “yellow dogs are cooler than brown cats”

以下是可以替换的不同选项:

substitutions = {“yellow” => “black”, “brown” => “grey”}

如何获得以下输出?

["black dogs are cooler than brown cats", "black dogs are cooler than grey cats", "yellow dogs are cooler than brown cats", "yellow dogs are cooler than grey cats"]

到目前为止,我只有这个,如您所见,它并没有获得所有选项:

substitutions.each do |key, value|
    puts my_string.sub(key, value) if my_string.include? key
end

【问题讨论】:

  • 嗯。您想要的输出似乎不完整;你不想考虑其他两种可能性吗:["yellow dogs are cooler than brown cats", "yellow dogs are cooler than grey cats"]
  • 感谢您的关注。已添加。

标签: ruby


【解决方案1】:

你真正需要的是把它转过来

substitutions = {“yellow” => “black”, “brown” => “grey”}

进入这个:

[{"yellow"=>"yellow", "brown"=>"brown"},
 {"yellow"=>"yellow", "brown"=>"grey"},
 {"yellow"=>"black", "brown"=>"brown"},
 {"yellow"=>"black", "brown"=>"grey"}]

然后您可以简单地循环上面的内容并获得所需的输出(您最初省略了身份转换,但包含它是最直接的)。这是将substitutions 更改为的一种方法:

substitutions.to_a[0].product(substitutions.to_a[1]).map do |ary|
  Hash[substitutions.keys.zip ary]
end 

那么就很简单了:

_.each do |h|
  p my_string.split.map {|word| h.fetch(word,word) }.join(' ')
end
"yellow dogs are cooler than brown cats"
"yellow dogs are cooler than grey cats"
"black dogs are cooler than brown cats"
"black dogs are cooler than grey cats"

这里我选择了 split -> sub each word -> rejoin over a global sub 操作,因为您可能想要替换“brown”而不是“brownie”。另一方面,这并不能很好地处理标点符号,因此您可以选择使用sub 或更复杂的正则表达式操作。由你决定。

【讨论】:

    【解决方案2】:

    这是一个通用解决方案,适用于任意数量的替换(不仅仅是两个):

    my_string = "yellow dogs are cooler than brown cats"
    substitutions = {"yellow"=>"black", "brown"=>"grey", "cooler"=>"sweeter"}
    keys = substitutions.keys           #=> ["yellow","brown","cooler"]
    regx = /\b#{Regexp.union(keys)}\b/  #=> /\b(?:yellow|brown|cooler)\b/
    axes = substitutions.to_a           #=> [["yellow", "black"], ["brown", "grey"], ["cooler", "sweeter"]]
    maps = axes.shift.product(*axes).map{ |*vals| Hash[ keys.zip(*vals) ] }
    maps.each{ |map| p map, my_string.gsub(regx){ |match| map[match] } }
    
    #=> {"yellow"=>"yellow", "brown"=>"brown", "cooler"=>"cooler"}
    #=> "yellow dogs are cooler than brown cats"
    
    #=> {"yellow"=>"yellow", "brown"=>"brown", "cooler"=>"sweeter"}
    #=> "yellow dogs are sweeter than brown cats"
    
    #=> {"yellow"=>"yellow", "brown"=>"grey", "cooler"=>"cooler"}
    #=> "yellow dogs are cooler than grey cats"
    
    #=> {"yellow"=>"yellow", "brown"=>"grey", "cooler"=>"sweeter"}
    #=> "yellow dogs are sweeter than grey cats"
    
    #=> {"yellow"=>"black", "brown"=>"brown", "cooler"=>"cooler"}
    #=> "black dogs are cooler than brown cats"
    
    #=> {"yellow"=>"black", "brown"=>"brown", "cooler"=>"sweeter"}
    #=> "black dogs are sweeter than brown cats"
    
    #=> {"yellow"=>"black", "brown"=>"grey", "cooler"=>"cooler"}
    #=> "black dogs are cooler than grey cats"
    
    #=> {"yellow"=>"black", "brown"=>"grey", "cooler"=>"sweeter"}
    #=> "black dogs are sweeter than grey cats"
    

    这里的关键是product 调用,它将[[1,2],[3,4],[5,6]] 变成:

    [[1, 3, 5],
     [1, 3, 6],
     [1, 4, 5],
     [1, 4, 6],
     [2, 3, 5],
     [2, 3, 6],
     [2, 4, 5],
     [2, 4, 6]]
    

    换句话说,调用数组和传入的所有数组的所有组合。

    将正则表达式与gsub 一起使用可以提高效率,对每个完整的替换集执行一次字符串遍历。 gsub 的块形式产生找到的文本,然后用于查找所需的替换(有时与原始字符串相同)。

    【讨论】:

      【解决方案3】:

      我会这样做:

      my_string = "yellow dogs are cooler than brown cats"
      substitutions = {"yellow" => "black", "brown" => "grey"}
      
      keys = substitutions.keys
      arry_of_comb = 0.upto(substitutions.size).flat_map do |num|
        keys.combination(num).map do |ary| 
          my_string.gsub(/\b#{Regexp.union(ary)}\b/,substitutions) 
        end
      end
      arry_of_comb
      # => ["yellow dogs are cooler than brown cats",
      #     "black dogs are cooler than brown cats",
      #     "yellow dogs are cooler than grey cats",
      #     "black dogs are cooler than grey cats"]
      

      【讨论】:

      • 酷。如果有两个替代选项,我怎么能让它工作?例如,substitutions = {"yellow" => "black", "brown" => "grey", "brown" => "blue"}
      • @user2270029 从我类似的answer 那里得到一些想法。
      【解决方案4】:
      my_string = "yellow dogs are cooler than brown cats"
      
      substitutions = {"yellow" => "black", "brown" => "grey"}
      
      substitutions.each do |k,v|
        if my_string.include?(k)
          my_string.sub! k, v
        end
      end
      
      puts my_string
      

      输出:黑狗比灰猫更酷

      【讨论】:

      • 这是一种变体,但正如我上面所说,我需要所有可能的变体。请查看所需的输出。谢谢。
      【解决方案5】:

      另一种方式:

      my_array = my_string.split.map(&:strip)
      
      substitutions.to_a
                   .repeated_permutation(subs.size)
                   .map { |a| Hash[a.uniq] }
                   .uniq
                   .map { |h| my_array.map { |w| h.key?(w) ? h[w] : w }.join(' ') }
                   .concat([my_string])
                   .uniq
      

      在损失一些效率的情况下,uniq 的前两次出现中的一个或两个都可以省略。

      步骤:

      my_string = "yellow dogs are cooler than brown cats"
      substitutions = {"yellow"=>"black", "brown"=>"grey", "cooler"=>"neater"}
      
      a = substitutions.to_a  # 27 elements
        #=> [["yellow", "black"], ["brown", "grey"], ["cooler", "neater"]] 
      b = a.repeated_permutation(subs.size)
        #=> => #<Enumerator: [["yellow", "black"],...
        b.to_a
        #=> [[["yellow", "black"], ["yellow", "black"], ["yellow", "black"]],
         #   [["yellow", "black"], ["yellow", "black"], ["brown", "grey"]],
         #   [["yellow", "black"], ["yellow", "black"], ["cooler", "neater"]],
         #   [["yellow", "black"], ["brown", "grey"], ["yellow", "black"]],
         #   ...
         #   [["cooler", "neater"], ["cooler", "neater"], ["cooler", "neater"]]] 
      
      c = b.map {|a| Hash[a.uniq]} # 27 elements
        #=> [{"yellow"=>"black"},
         #   {"brown"=>"grey", "yellow"=>"black"},
         #   {"cooler"=>"neater", "yellow"=>"black"},
         #   {"brown"=>"grey", "yellow"=>"black"},
         #   {"brown"=>"grey", "yellow"=>"black"},
         #   ...
         #   {"brown"=>"grey", "cooler"=>"neater", "yellow"=>"black"},
         #   ...
         #   {"cooler"=>"neater"}]
      
      d = c.uniq
         #=> [{"yellow"=>"black"},
         #    {"brown"=>"grey", "yellow"=>"black"},
         #    {"cooler"=>"neater", "yellow"=>"black"},
         #    {"brown"=>"grey", "cooler"=>"neater", "yellow"=>"black"},
         #    {"brown"=>"grey"},
         #    {"brown"=>"grey", "cooler"=>"neater"},
         #    {"cooler"=>"neater"}] 
      
      e = d.map {|h| my_array.map { |w| h.key?(w) ? h[w] : w }.join(' ') }
           .concat([my_string])
        #=> ["black dogs are cooler than brown cats",
        #    "black dogs are cooler than grey cats",
        #    "black dogs are neater than brown cats",
        #    "black dogs are neater than grey cats",
        #    "yellow dogs are cooler than grey cats",
        #    "yellow dogs are neater than grey cats",
        #    "yellow dogs are neater than brown cats",
        #    "yellow dogs are cooler than brown cats"] 
      
      e.uniq
        # No effect here.  Only relevant for substitutions such as
        # "black=>"yellow" and "grey=>yellow", or "black"=>"black"
      

      【讨论】:

        猜你喜欢
        • 2011-08-29
        • 1970-01-01
        • 2014-11-05
        • 2022-01-07
        • 1970-01-01
        • 1970-01-01
        • 2012-11-14
        • 1970-01-01
        • 2015-10-08
        相关资源
        最近更新 更多