Reputation: 189
I have an array with elements that are arrays of varying sizes. For example:
[[3],[11,2],[11,2],[3]]
I would like to find permutations of all of the individual items in the nested arrays. For the array above, I'd like a return value of:
[
[3, 11, 11, 3],
[3, 11, 2, 3],
[3, 2, 11, 3],
[3, 2, 2, 3]
]
I have a solution that works, but it seems particularly long-winded:
array = [[3],[11,2],[11,2],[3]]
array.product(*array).map { |e| e.drop(1) }.uniq
How should I implement a recursive approach to this, and how would that work? I am having trouble wrapping my head around this.
Upvotes: 2
Views: 312
Reputation: 110675
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]]
Upvotes: 5
Reputation: 739
Initialization:
@arr = [[3],[11,2],[11,2],[3]]
@perms = []
Function Definition:
def recursion(idx, temp = [])
if (idx == @arr.size) then @perms.push(temp.clone); return end
@arr[idx].each { |x| recursion(idx+1, temp << x); temp.pop }
end
Call :
recursion(0)
p @perms
=> [[3, 11, 11, 3], [3, 11, 2, 3], [3, 2, 11, 3], [3, 2, 2, 3]]
Upvotes: 1