This should do the job in recent Ruby versions:
a.length.downto(1).map{|i| a.combination(i).map{|sub| sub.inject(&:&)}}
#=> [[[]], [[], [3, 4], [2], [1]], [[3, 4], [2], [2, 3, 4], [1], [1, 3, 4], [1, 2]], [[2, 3, 4], [1, 3, 4], [1, 2], [1, 2, 3, 4]]]
Here's a related question with similar solution. The "trick" is in method Array#&
, which calculates the intersection (as a set operation) of the two arrays. It is associative operation, so we can apply it on each subarray in turn, keeping the accumulated result, hence inject
is perfect for it. In short, array.inject(&:&)
will result with a greatest common subset of elements in every member of array
. &:&
is just a Ruby shorthand for making a Proc
out of method named &
and submitting it as a block to inject
, instead of writing:
array.inject{|a,e| a & e}