Ruby - Permutation Between Elements of an Array

ruby - Permutation between different elements in an array

ar = [["a, b, c"], ["lol1, lol2, lol3"], ["so1, so2, so3"]]
p maybe_this = ar.map{|sub_ar| sub_ar.first.split(', ')}
#[["a", "b", "c"], ["lol1", "lol2", "lol3"], ["so1", "so2", "so3"]]
idx = [2,1,3]
#indexing of an array is zero-based
p idx.map!{|i| i-1} #[1,0,2]
p res = maybe_this.map{|sub_ar| sub_ar.values_at(*idx)}
#[["b", "a", "c"], ["lol2", "lol1", "lol3"], ["so2", "so1", "so3"]]

The short story: the values_at method takes multiple arguments; *idx splats an array into multiple arguments.

Permutations in Ruby - unsure how to handle

First, check size of that permutation

a.permutation(10).size
=> 670442572800

It's huge. What you can do instead is to use Array#repeated_permutations on smaller array. Check it here:

b = [1, 2] # Only unique elements
b.repeated_permutation(10) # Returns enumerable
b.repeated_permutation(10).to_a # Creates array with all of permutations

Those permutations are already unique (which u can check by printing it size with and without Array#uniq )

Finding all permutations of numbers plucked from an array which sum to 16

For all permutations, including duplicates, one might use Array#repeated_permutation:

d = [2,3,4,5,6,7,8]
number_of_divisions = [3,4,5]
number_of_divisions.flat_map do |n|
d.repeated_permutation(n).reject do |p| # no need `to_a`
p.inject(:+) != 16
end
end

or, even better with Array#repeated_combination:

number_of_divisions.flat_map do |n|
d.repeated_combination(n).reject do |p| # no need `to_a`
p.inject(:+) != 16
end
end

Generate combinations of values from multiple arrays

If you want all the possible combinations, there's no alternative other than iterating through each of the elements for all arrays.

Creating hashes is not difficult either.

Try this.

a = [1, 2, 3, 4, 5]
b = ['A', 'B', 'C', 'D', 'E']
c = ['J', 'K', 'L', 'M', 'N']
d = ['v', 'w', 'x', 'y', 'z']

result = []

a.each do |a_elem|
b.each do |b_elem|
c.each do |c_elem|
d.each do |d_elem|
result << {a: a_elem, b: b_elem, c: c_elem, d: d_elem}
end
end
end
end

puts "#{result}"

I believe this is what you are looking for.

Combination of two arrays in Ruby

You can use product to get the cartesian product of the arrays first, then collect the function results.

a.product(b) => [[1, 3], [1, 4], [2, 3], [2, 4]]

So you can use map or collect to get the results. They are different names for the same method.

a.product(b).collect { |x, y| f(x, y) }

Find all permutations of Ruby array of arrays

What you need is the cartesian product. Something like:

[1].product([2,3],[4,5],[6]) # => [[1, 2, 4, 6], [1, 2, 5, 6], [1, 3, 4, 6], [1, 3, 5, 6]]

Find all the possible permutations using Ruby and recursion

To see what the difficulty may be, let's try it with an even simpler example:

string = "ab"

Your desired result is ["ab", "ba"]. Let's see what you get:

string.size #=> 2

so we don't return when

return [string] if string.size < 2
#=> return ["ab"] if "ab".size < 2

is executed.

Next we calculate:

chr = string.chars.first #=> "a"

Notice that a more direct way of making this calculation is as follows:

chr = string[0]  #=> "a"

or, better, using String#chr,

chr = string.chr #=> "a"

The latter illustrates why chr is not the best choice for the variable name.

Next

perms = permutation(string[1..-1])
#=> = permutation("b")

I will now indent the return values to emphasize that we are calling permutation a second time. permuation's argument is:

  string #=> "b"

Now when we execute:

  return [string] if string.size < 2
#=> return ["b"] if "b".size < 2

we return ["b"], so (back to original call to permutation):

perms = ["b"]

to go with chr => "a", calculated earlier. Next:

result = []

for perm in perms
for i in (0..perm.size)
result << (perm[0..i] + chr + perm[i..-1])
end
end

As perms contains only the single element "b", the two for loops simplify to:

for i in (0.."b".size)
result << ("b"[0..i] + "a" + "b"[i..-1])
end

which is:

for i in (0..1)
result << ("b"[0..i] + "a" + "b"[i..-1])
end

Notice that "b"[0..0], "b"[0..1] and "b"[0..-1] all equal "b"[0], which is just "b", and "b"[1..-1] #=> ''. Therefore, when i => 0, we execute:

result << ("b"[0..0] + "a" + "b"[0..-1])
#=> result << ("b" + "a" + "b")
#=> result << "bab"

and when i => 1:

result << ("b"[0..1] + "a" + "b"[1..-1])
#=> result << ("b" + "a" + "")
#=> result << "ba"

so:

result => ["bab" + "ba"]

which clearly is not what you want.

What you need to do is is change the double for loops to:

for perm in perms
result << chr + perm
for i in (1..perm.size-1)
result << (perm[0..i-1] + chr + perm[i..-1])
end
result << perm + chr
end

which could be written more compactly by employing the method String#insert:

for perm in perms
for i in (0..perm.size)
result << perm.dup.insert(i,chr)
end
end

which you would normally see written like this:

perms.each_with_object([]) do |perm, result|
(0..perm.size).each { |i| result << perm.dup.insert(i,chr) }
end

Notice that we have to .dup the string before sending insert, as insert modifies the string.

Doing it like this, you don't need result = []. Neither do you need return result, as parms.each_with_object returns result and if there is no return statement, the method returns the last quantity calculated. Also, you don't need the temporary variable perms (or ch, if desired).

Putting this altogether, we have:

def permutation(string)
return [string] if string.size < 2
ch = string[0]
permutation(string[1..-1]).each_with_object([]) do |perm, result|
(0..perm.size).each { |i| result << perm.dup.insert(i,ch) }
end
end

Let's try it:

permutation("ab")
#=> ["ab", "ba"]
permutation("abc")
#=> ["abc", "bac", "bca", "acb", "cab", "cba"]
permutation("abcd")
#=> ["abcd", "bacd", "bcad", "bcda", "acbd", "cabd",
# "cbad", "cbda", "acdb", "cadb", "cdab", "cdba",
# "abdc", "badc", "bdac", "bdca", "adbc", "dabc",
# "dbac", "dbca", "adcb", "dacb", "dcab", "dcba"]

Eki, which one are you in the picture?

Ruby: Permutation on an Array

Please test in detail before use:

x = [1,0]
n = 3

def perm(a, n)
l = a.length
(l**n).times do |i|
entry = []
o = i
n.times do
v = o % l
entry << a[v]
o /= l
end
yield(i, entry)
end
end

perm(x, n) do |i, entry|
puts "#{i} #{entry.reverse.inspect}"
end

prints

0 [0, 0, 0]
1 [0, 0, 1]
2 [0, 1, 0]
3 [0, 1, 1]
4 [1, 0, 0]
5 [1, 0, 1]
6 [1, 1, 0]
7 [1, 1, 1]


Related Topics



Leave a reply



Submit