问题
I have an array of strings:
["ABC", "GHI"]
ad I want all the 'letter' combinations, as reads from left to right, i.e.
["AG", "AH", "AI", "BG", "BH", "BI", "CG", "CH", "CI"]
but not
"GA", "GB", "HA", etc.
Similarly,
["ABC", "DEF", "GHI"]
should generate
["ADG", "ADH", "ADI", "AEG", "AEH", "AEI", "AFG", "AFH", "AFI", "BDG", "BDH",
"BDI", "BEG", "BEH", "BEI", "BFG", "BFH", "BFI", "CDG", "CDH", "CDI", "CEG",
"CEH", "CEI", "CFG", "CFH" "CFI"]
but not
"DAG", "GAD" or "GFA"
回答1:
This is what you need:
a = ["ABC","DEF", "GHI"]
a.map(&:chars).reduce(&:product).map(&:join)
By the way, you made some errors in your example output, there should never be strings starting with an E or an F according to your specification. So I suppose instead of "ECH", "ECI", "FCG", "FCH", "FCI"
you meant "CEH", "CEI", "CFG", "CFH", "CFI"
.
Edit:
chars
returns an Enumerator, not an array, and in Ruby versions before 2.0 those don't have a product
method. So in those versions, just use a to_a
like this:
a.map(&:chars).map(&:to_a).reduce(&:product).map(&:join)
回答2:
a = ["ABC","DEF", "GHI"]
first, *rest = a.map{|s| s.each_char.to_a}
first.product(*rest).map(&:join)
# =>
# ["ADG", "ADH", "ADI", "AEG", "AEH", "AEI", "AFG", "AFH", "AFI", "BDG", "BDH", "BDI",
# "BEG", "BEH", "BEI", "BFG", "BFH", "BFI", "CDG", "CDH", "CDI", "CEG", "CEH", "CEI",
# "CFG", "CFH", "CFI"]
Benchmarks comparing with @ggPeti’s solution:
t = Time.now
50000.times do
a.map(&:chars).reduce(&:product).map(&:join)
end
puts Time.now - t
# => 2.037303374
t = Time.now
50000.times do
first, *rest = a.map{|s| s.each_char.to_a}
first.product(*rest).map(&:join)
end
puts Time.now - t
# => 1.670047516
回答3:
A recursive solution:
def doit(b)
recurse(b.map(&:chars))
end
def recurse(a)
(a.size==2 ? a.first.product(a.last) :a.shift.product(recurse a)).map(&:join)
end
doit(["ABC", "DEF", "GHI"])
#=> ["ADG", "ADH", "ADI", "AEG", "AEH", "AEI", "AFG", "AFH", "AFI",
# "BDG", "BDH", "BDI", "BEG", "BEH", "BEI", "BFG", "BFH", "BFI",
# "CDG", "CDH", "CDI", "CEG", "CEH", "CEI", "CFG", "CFH", "CFI"]
doit(["ABC", "DE", "FGHI"])
#=> ["ADF", "ADG", "ADH", "ADI", "AEF", "AEG", "AEH", "AEI",
# "BDF", "BDG", "BDH", "BDI", "BEF", "BEG", "BEH", "BEI",
# "CDF", "CDG", "CDH", "CDI", "CEF", "CEG", "CEH", "CEI"]
来源:https://stackoverflow.com/questions/22429190/ruby-how-to-generate-the-possible-sequential-combination-of-letters-from-an-ar