如何获取字符串中可用键的所有组合

时间:2016-01-26 00:23:59

标签: ruby string substitution

我有一个这样的字符串:

'show -drum-, -drum- and -drum-'

每个/-[a-z]+-/键的一系列选项:

{
  '-drum-' => %w{kick snare hihat crash},
  ...
}

我想做出所有可能的替换,包括:

[
  'show kick, snare and hihat',
  'show kick, hihat and snare',
  'show snare, hihat and kick',
  'show snare, kick and hihat',
  'show hihat, snare and kick',
  'show hihat, kick and snare',
  'show crash, kick and snare',
  'show crash, snare and kick',
  'show hihat, snare and crash',
  ...
]

理想情况下,这会发生而不会重复,虽然我会接受一个可以返回的解决方案,例如“显示踢,踢和踢”等。

散列中还有其他关键替换,所以我也必须对它们进行独特的组合。

3 个答案:

答案 0 :(得分:2)

a = ['kick','snare', 'hihat']
a.permutation.each do |p|
  puts "play %s, %s and %s" % p
end

内置permutation功能。在上面的示例中,将所有内容存储在数组中,然后只需调用permutation。之后使用p并插入目标字符串中的值。

输出结果为:

play kick, snare and hihat
play kick, hihat and snare
play snare, kick and hihat
play snare, hihat and kick
play hihat, kick and snare
play hihat, snare and kick

这是一般化形式:

rep = {
  '-drum-' => %w{kick snare hihat crash},
  '-zoo-' => %w{zebra lion dog},
  '-one-' => %w{one},
  '-ping-' => %w{pong noreply}
}

template = 'show -drum- on -zoo-, -one- -ping- for -drum-, -ping- for -drum- or -drum- -zoo- -zoo-'
accumulator = []
accumulator << template

rep.keys.each do |key|
  new_accumulator = []
  accumulator.each do |acc|
    transformed_template = acc.gsub(key, '%s')
    rep[key].permutation.each do |p|
     new_accumulator << transformed_template % p
    end
  end
  accumulator = new_accumulator
end

accumulator.each do |fin|
  puts fin
end

答案 1 :(得分:2)

有趣的挑战。

def each_replacement(pattern, repl_keys)
  return enum_for(__method__, pattern, repl_keys) unless block_given?

  pattern.gsub!('%', '%%')
  keys = repl_keys.keys
  key_counts = Hash[keys.map { |key| [key, pattern.scan(key).count] }]
  key_permutations = repl_keys.lazy.map { |key, repl|
    combinations = repl.combination(key_counts[key])
    combinations.flat_map { |comb|
      comb.permutation.to_a
    }
  }.inject(&:product)
  key_permutations.each do |perm|
    text = pattern
    keys.zip(perm).each do |key, repl|
      text = text.gsub(key, '%s') % repl
    end
    yield text
  end
end

pattern = '-action- -drum-, -drum- and -drum-'
keys = {
  '-drum-' => %w{kick snare hihat crash},
  '-action-' => %w{hit smash}
}
puts each_replacement(pattern, keys).to_a

答案 2 :(得分:0)

使用单个目标替换对:

target = /-drum-/
replacement = %w{kick snare hihat}
a = ["show -drum-, -drum- and -drum-"]
while a.first =~ target
  a = a.flat_map{|s| replacement.map{|r| s.sub(target, r)}}
end
a # => ["show kick, kick and kick", "show kick, kick and snare", "show kick, kick and hihat", "show kick, snare and kick", "show kick, snare and snare", "show kick, snare and hihat", "show kick, hihat and kick", "show kick, hihat and snare", "show kick, hihat and hihat", "show snare, kick and kick", "show snare, kick and snare", "show snare, kick and hihat", "show snare, snare and kick", "show snare, snare and snare", "show snare, snare and hihat", "show snare, hihat and kick", "show snare, hihat and snare", "show snare, hihat and hihat", "show hihat, kick and kick", "show hihat, kick and snare", "show hihat, kick and hihat", "show hihat, snare and kick", "show hihat, snare and snare", "show hihat, snare and hihat", "show hihat, hihat and kick", "show hihat, hihat and snare", "show hihat, hihat and hihat"]
a.length # => 27