Reputation: 398
I'm hopelessly trying to write a method to manipulate an array in ruby. I'm trying to generate all in-order permutations of an array where each item is in turn replaced by an outside item. An example...
Given input:
arr = ["a", "b", "c"]
Desired output:
newArr = [ ["a", "b", "c"], ["a", "b", "*"], ["a", "*", "c"], ["a", "*", "*"], ["*", "b", "c"], ["*", "b", "*"], ["*", "*", "c"], ["*", "*", "*"] ]
Any help would be greatly appreciated. Thank you!
Upvotes: 2
Views: 1694
Reputation: 15478
I don't understand your example order, either, but ignoring that, here's a solution in one line:
(0...(2**a.size)).map {|x| (0...a.size).map {|y| x & 2**y == 0 ? a[y] : val}}
Upvotes: 8
Reputation: 3137
Similar to oylenshpeegui's method:
def toggle(arr, sub)
format = "%0#{arr.length}b"
(0...2**(arr.length)).to_a.map do |i|
sprintf(format,i).split('').zip(arr).map { |x| x[0] == "0" ? x[1] : sub }
end
end
The split/zip combo matches each digit of the binary expansion of the index with the element it is selecting. The map at the end uses the digit to decide if it should return the array element or the substitution.
Upvotes: 1
Reputation: 3424
I'm not sure permutation is the right word. If you count in binary, then you are replacing the things if there is a one. Here's that in Ruby:
def mike(arr, sub)
format = sprintf("%%0%db", arr.length)
m = Array.new
0.upto(2**arr.length-1) { |i|
bits = sprintf(format, i).split('')
a = Array.new
0.upto(arr.length-1) { |j|
if bits[j] == '0' then
a << arr[j]
else
a << sub
end
}
m[i] = a
}
return m
end
arr = ["a", "b", "c"]
p mike(arr, '*')
Is that if-then-else better with a ternary operator?
a <<= bits[j] == '0' ? arr[j] : sub
There must be a cleverer (or, at least more Rubyesque) way to do this, but it seems to produce the desired output.
ETA: Oops! My second and third items don't agree with yours. I guess I don't know what order you mean.
Upvotes: 2