Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to combination/permutation in ruby?

Tags:

ruby

I've this familiar question that looks like permutation/combination of the Math world.

How can I achieve the following via ruby?

badges = "1-2-3"

badge_cascade = []
badges.split("-").each do |b|
  badge_cascade << b
end

Gives: => ["1", "2", "3"]

But I want it to be is:

=> ["1", "2", "3", 
  "1-2", "2-3", "3-1", "2-1", "3-2", "1-3", 
  "1-2-3", "2-3-1", "3-1-2"]
like image 572
Autodidact Avatar asked Jan 26 '12 13:01

Autodidact


2 Answers

Functional approach:

bs = "1-2-3".split("-")
strings = 1.upto(bs.size).flat_map do |n| 
  bs.permutation(n).map { |vs| vs.join("-") } 
end
#=> ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]
like image 170
tokland Avatar answered Oct 02 '22 15:10

tokland


You ned to use Array#permutation method in order to get all permutations:

arr = "1-2-3".split '-' # => ["1", "2", "3"]
res = (1..arr.length).reduce([]) { |res, length|
  res += arr.permutation(length).to_a
}.map {|arr| arr.join('-')}

puts res.inspect
# => ["1", "2", "3", "1-2", "1-3", "2-1", "2-3", "3-1", "3-2", "1-2-3", "1-3-2", "2-1-3", "2-3-1", "3-1-2", "3-2-1"]

Let me explain the code:

  1. You split string into array passing separator '-' to String#split method

  2. You need all permutations of length 1, 2, 3. Range 1..arr.length represents all these lengths.

  3. You collect an array of all permutations using Enumerable#reduce. You will get array of arrays here:

    [["1"], ["2"], ["3"], ["1", "2"], ["1", "3"], ["2", "1"], ["2", "3"], ["3", "1"], ["3", "2"], ["1", "2", "3"], ["1", "3", "2"], ["2", "1", "3"], ["2", "3", "1"], ["3", "1", "2"], ["3", "2", "1"]]
    
  4. You transform all subarrays of this array into strings using Array#join with your '-' separator inside of Enumerable#map

like image 30
Aliaksei Kliuchnikau Avatar answered Oct 02 '22 15:10

Aliaksei Kliuchnikau