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

How to get all combinations of available keys in a string

我有这样的字符串:

'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',
  ...
]

理想情况下,这不会重复发生,尽管我会接受 return 的解决方案,例如 'show kick, kick and kick',等等

哈希中还有其他键替换,所以我也必须对这些进行独特的组合。

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

有一个built-inpermutation函数。在上面的示例中,将所有内容存储在一个数组中,然后调用 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

单 target-replacement 对:

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

有趣的挑战。

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