Creating Permutations from a Multi-Dimensional Array in Ruby

Creating permutations from a multi-dimensional array in Ruby

Yup, Array#product does just that (Cartesian product):

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

Another variant:

a.inject(&:product).map(&:flatten)
#=> [[1, 3, 4], [1, 3, 5], [1, 3, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6]]

Condensing multidimensional array of permutations into groups

I'm not quite sure if I correctly understand the problem, but given this array:

a = [[1, 12], [1, 5], [1, 6], [5, 12], [6, 12], [12, 5], [12, 6]]

I think you can group the left-hand items by the right-hand items:

h1 = Hash.new { |h, k| h[k] = [] }
a.each { |k, v| h1[v] << k }
h1
#=> {12=>[1, 5, 6], 5=>[1, 12], 6=>[1, 12]}

And apply the same transformation again:

h2 = Hash.new { |h, k| h[k] = [] }
h1.each { |k, v| h2[v] << k }
h2
#=> {[1, 5, 6]=>[12], [1, 12]=>[5, 6]}

This gives:

h2.to_a
#=> [
# [[1, 5, 6], [12]],
# [[1, 12], [5, 6]]
# ]

In recent versions of Ruby you could write it as:

a.group_by(&:last).transform_values { |v| v.map(&:first) }
.group_by(&:last).transform_values { |v| v.map(&:first) }
.to_a
#=> [
# [[1, 5, 6], [12]],
# [[1, 12], [5, 6]]
# ]

The condensed array can be expanded via:

[[[1, 5, 6], [12]], [[1, 12], [5, 6]]].flat_map { |a, b| a.product(b) }
#=> [[1, 12], [5, 12], [6, 12], [1, 5], [1, 6], [12, 5], [12, 6]]

Note that this attempt only works for sub-arrays with two elements, but it should get you started.

Creating combination from a multi-dimensional array in Ruby


first, *rest = [['monday', 'saturday'], ['beginner'], ['kid', 'adult']]
.map{|a| [nil, *a]}
first.product(*rest).map{|a| a.compact.join("-")} - [""]

How to recursively find permutations of two dimensional array in Ruby

The conventional way of solving this problem is to use the methods Array#product and Array#drop.

arr = [[3], [11,2], [11,2,7], [4]]

arr.first.product(*arr.drop(1))
#=> [[3, 11, 11, 4], [3, 11, 2, 4], [3, 11, 7, 4],
# [3, 2, 11, 4], [3, 2, 2, 4], [3, 2, 7, 4]]

If any element of arr contains duplicates the return value will also contain duplicates. If duplicates are not wanted, use

arr.map(&:uniq).first.product(*arr.drop(1))

The asker has, however, requested a recursive solution. That could be written as follows:

def prod(arr)
return arr if arr.size == 1
t = prod(arr.drop(1))
arr.first.flat_map { |x| t.map { |a| [x] + a } }
end

prod arr
#=> [[3, 11, 11, 4], [3, 11, 2, 4], [3, 11, 7, 4],
# [3, 2, 11, 4], [3, 2, 2, 4], [3, 2, 7, 4]]

Combine array of array into all possible combinations, forward only, in Ruby

Know your Array#product:

a = [['1','2'],['a','b'],['x','y']]
a.first.product(*a[1..-1]).map(&:join)

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.

Ruby all possible permutations of an array of arrays (one liner?)

With Array#permutation:

permutations = (1..6).to_a.permutation.map(&:join)
# ["123456", "123465", "123546", ..., "654312", "654321"]

Generate array of limited combinations from another array

You can use Array#permutation if you don't want repetetions in the subarrays.

  • col1 ∈ [1; 3]
  • row2 ∈ [0; 3]
days.permutation(col).to_a.slice(0, row)

Demonstration

If you want repetitions in the subarrays, you can use Array#repeated_permutation.

  • col ∈ [1; 3]
  • row ∈ [0; 33(= 27)]:
days.repeated_permutation(col).to_a.slice(0, row)

Demonstration

If you want repetitions in the subarrays and also expand your column number to the custom, independent from length of the original array number, you can use Array#repeated_combination.

  • col ∈ [1; ∞3 )
  • row ∈ [0; colcol]:
days.repeated_combination(col).to_a.slice(0, row)

Demonstration


1 col is the number of elements in each subarray.

2 row is the number of subarrays in the desired 2D array.

3 The upper bound is specified as to represent that this value is not bounded by the length of the original array.

Creating a combination from arrays and turn it into a multi-dimensional permutations in javascript?

You are looking to get the subsets of length N from your selection of arrays, then create the cartesian product of each subset.

// returns power set of arr filtered by length
function powerset(arr, len, pref=[]) {
if (len == 0) return [pref];
if (len > arr.length) return [];
if (len == arr.length) return [pref.concat(arr)]; // premature optimisation
const next = arr.slice(1);
return powerset(next, len-1, [...pref, arr[0]]).concat(powerset(next, len, pref));
}
// returns cartesian product of the arrays in the argument
function cartesian(arg) {
var r = [], max = arg.length-1;
function helper(arr, i) {
for (var j=0, l=arg[i].length; j<l; j++) {
var a = arr.slice(0); // clone arr
a.push(arg[i][j]);
if (i==max)
r.push(a);
else
helper(a, i+1);
}
}
helper([], 0);
return r;
}
var arrays = [
['a', 'b'],
['c'],
['d', 'e', 'f'],
['x', 'y', 'z']
];
console.log(powerset(arrays, 2).flatMap(cartesian));
console.log(powerset(arrays, 3).flatMap(cartesian));
console.log(powerset(arrays, 4).flatMap(cartesian));


Related Topics



Leave a reply



Submit