All possible combinations of selected character substitution in a string in ruby

前端 未结 5 916
悲&欢浪女
悲&欢浪女 2020-12-18 11:07

I was wondering if there is a simple way to do every combination of selected character substitutions in ruby in a simple way.

An example:

    string          


        
相关标签:
5条回答
  • 2020-12-18 11:40

    I'd do as follows using String#gsub(pattern, hash) :

    string = "this is a test"
    subs = {'a'=>'@','i'=>'!','s'=>'$'} # copied from @ArupRakshit
    keys = subs.keys
    

    And core code:

    1.upto(keys.length).flat_map { |i| 
      keys.combination(i).flat_map { |c| string.gsub(/[#{c.join}]/, subs) } 
    }
    

    Output:

    => ["this is @ test",
     "th!s !s a test",
     "thi$ i$ a te$t",
     "th!s !s @ test",
     "thi$ i$ @ te$t",
     "th!$ !$ a te$t",
     "th!$ !$ @ te$t"]
    
    0 讨论(0)
  • 2020-12-18 11:41
    string = "this is a test"
    subs = ['a'=>'@','i'=>'!','s'=>'$']
    
    subs = subs.first.map(&:to_a)
    1.upto(subs.length).each do |n|
      subs.combination(n).each do |a|
        p a.each_with_object(string.dup){|pair, s| s.gsub!(*pair)}
      end
    end
    
    0 讨论(0)
  • 2020-12-18 11:44

    I'd do as below :

    string = "this is a test"
    subs = {'a'=>'@','i'=>'!','s'=>'$'}
    
    keys = subs.keys
    combinations = 1.upto(subs.size).flat_map { |i| keys.combination(i).to_a }
    
    combinations.each do |ary|
      new_string = string.dup
      ary.each { |c| new_string.gsub!(c,subs) }
      puts new_string
    end
    

    output

    this is @ test
    th!s !s a test
    thi$ i$ a te$t
    th!s !s @ test
    thi$ i$ @ te$t
    th!$ !$ a te$t
    th!$ !$ @ te$t
    
    0 讨论(0)
  • 2020-12-18 11:48

    Another way:

    string = "this is a test"
    subs   = [{"a"=>"@"}, {"i"=>"!"}, {"s"=>"$"}]
    
    subs.repeated_combination(subs.size)
        .map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}}
        .uniq
      #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t",
      #    "th!s !s a test", "th!$ !$ a te$t", thi$ i$ a te$t"]
    

    Explanation:

    a = subs.repeated_combination(subs.size)
      # Enumerator...
      a.to_a 
      # [[{"a"=>"@"},{"a"=>"@"},{"a"=>"@"}], [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}],
      #  [{"a"=>"@"},{"a"=>"@"},{"s"=>"$"}], [{"a"=>"@"},{"i"=>"!"},{"i"=>"!"}],
      #  [{"a"=>"@"},{"i"=>"!"},{"s"=>"$"}], [{"a"=>"@"},{"s"=>"$"},{"s"=>"$"}],
      #  [{"i"=>"!"},{"i"=>"!"},{"i"=>"!"}], [{"i"=>"!"},{"i"=>"!"},{"s"=>"$"}],
      #  [{"i"=>"!"},{"s"=>"$"},{"s"=>"$"}], [{"s"=>"$"},{"s"=>"$"},{"s"=>"$"}]]
    
    b = a.map {|e| string.gsub(/./) {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}}
      #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!s !s @ test",
      #    "th!$ !$ @ te$t", "thi$ i$ @ te$t", "th!s !s a test", "th!$ !$ a te$t",
      #    "th!$ !$ a te$t", "thi$ i$ a te$t"]
    

    To see how b is computed, consider the second element of a that is passed to the block:

        e = [{"a"=>"@"},{"a"=>"@"},{"i"=>"!"}]
    

    Because of the regex, /./, gsub passes each character c of string to the block

        {|c| (g = e.find {|h| h.key?(c)}) ? g[c] : c}
    

    A search is made of e to determine if any of the three hashes has c as a key. If one is found, namely, g, the character c is replaced with g[c]; else, the character is left unchanged.

    Notice that the first two elements of e are the same. Efficiency could be improved by changing the first line to:

        subs.repeated_combination(subs.size).map(&:uniq)
    

    but efficiency is not one of the virtues of this approach.

    Returning to the main calculation, the final step is:

    b.uniq
      #=> ["this is @ test", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ @ te$t",
      #    "th!s !s a test", "th!$ !$ a te$t", "thi$ i$ a te$t"]
    
    0 讨论(0)
  • 2020-12-18 11:53

    A one-line functional solution

    string = "this is a test"
    subs = {'a'=>'@','i'=>'!','s'=>'$'}
    
    (1..subs.size).flat_map { |n| subs.keys.combination(n).to_a }.map { |c| string.gsub(/[#{c.join}]/, subs) }
    # => ["this is @ test", "th!s !s a test", "thi$ i$ a te$t", "th!s !s @ test", "thi$ i$ @ te$t", "th!$ !$ a te$t", "th!$ !$ @ te$t"]
    
    0 讨论(0)
提交回复
热议问题