Reputation: 302
What is the shortest way of getting all K-item combinations of an N-item array where K <= N? I managed to write down the one below :
> [1,2,3].instance_eval "(1..size).flat_map {|i| self.combination(i).to_a }"
=> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Any ideas how to get rid of "instance_eval"? It doesn't seem to be very elagant :\
Upvotes: 1
Views: 142
Reputation: 110655
arr = [1,2,3,4]
(2**arr.size).times.map do |i|
arr.each_with_index.with_object([]) { |(e,j),a| a << e if i[j] == 1 }
end
#=> [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3], [4], [1, 4],
# [2, 4], [1, 2, 4], [3, 4], [1, 3, 4], [2, 3, 4], [1, 2, 3, 4]]
You could, of course, sort the array that is returned however you like. For example:
(2**arr.size).times.map do |i|
arr.each_with_index.with_object([]) { |(e,j),a| a << e if i[j] == 1 }
end.sort_by { |a| [a.size,a] }
#=> [[],
# [1], [2], [3], [4],
# [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4],
# [1, 2, 3], [1, 2, 4], [1, 3, 4], [2, 3, 4],
# [1, 2, 3, 4]]
Upvotes: 1
Reputation: 106782
I would do something like this:
x = [1,2,3]
1.upto(x.size).flat_map { |i| x.combination(i).to_a }
#=> [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Upvotes: 2
Reputation: 10784
Here's a cool, short way to implement a "power set" function, if order/empty list doesn't matter:
>>> [nil].product(*[1, 2, 3].map { |x| [nil, x] }).map(&:compact)
[[], [3], [2], [2, 3], [1], [1, 3], [1, 2], [1, 2, 3]]
Upvotes: 2
Reputation: 7685
One version, hope it's correct.
x = [1, 2, 3]
1.upto(x.size).reduce([]) { |a, i| a + x.permutation(i).map(&:sort).uniq.to_a }
# => [[1], [2], [3], [1, 2], [1, 3], [2, 3], [1, 2, 3]]
Upvotes: 0