http://qs321.pair.com?node_id=976625


in reply to Combinations of array?

Late to the party and, not only that, but wearing the same outfit as some (see ambrus's link above). I think the best answer for you is toolic's. My answer that follows just fills in a few conceptual details for you about the Power Set, illustrated by two functions that do the job two different ways.

Earlier, I had copied this problem to my notepad and had misremembered your question as being about a string, "ABCD", rather than an array of elements. So both functions take in a string and return a list of strings. This makes my answer slightly different from the others in the recursive case and bulky in the enumeration case.

Power Set

Given a set, A, the set of all subsets of elements of A is called the power set of A, here denoted P(A). A power set, P(A), of finite set A has size 2N. So your example should have 16 results. (Note, one of those subsets is the empty set / empty string). Finding all combinations of elements of a set is an equivalent notion.

Power sets get very big, very fast, so in general you don't see many applications for power sets unless you are writing advertisements for how many ways customers can put condiments on their hamburgers. If this question is motivated by a real-world problem (i.e., one that doesn't get a grade) it would be interesting to some of us if you could post some details about it.

recursion

The first function, rpow, shows the recursive solution and its map block indicates that the results of the recursed function call are doubled, hence you can see how the 2N subsets are built up.

#!/usr/bin/env perl use Modern::Perl; sub rpow { my ($p, $q) = $_[0] =~ /(.)(.*)/; return $_[0] ? map { ($p.$_, $_) } rpow ($q) : ''; } say join ("\n", rpow 'ABCD');

enumeration

The second function, bpow, is a direct enumeration of the power set by using the on/off nature of a bit in the binary representation of a number as a representation for the in/out selection of an element of A for a given element of P(A). That is, it runs a bit-mask of each non-negative integer less than 2N against your string. It produces the same results as rpow (in reverse order).

#!/usr/bin/env perl use Modern::Perl; sub bpow { map { my $m = unpack("b*", pack("i*",$_)); $m =~ s/0/\0/g; $m =~ s/1/~"\0"/ge; $m & $_[0]; } 0..2**length($_[0])-1 } say join ("\n", bpow 'ABCD');