var a = [1,3,6,10,-1];
function combinations(array, n) {
}
combinations(a, 9) // should return...
[[1], [3], [6], [-1], [1,3], [1,6], [1,-1], [3,6], [3,-1], [6, -1], [10, -1], [1,3,-1], [3,6,-1], [1,6,-1], [1,3,6,-1]]
maybe i'm missing some correct answers but you get the idea. Really dying to know how to solve this!
@jcarpenter solution was so nice I just had to rework it for those that love ECMA5. This will not be as fast as the raw power of
for
, the modern methods have not had the length of time to be so highly optimised (and they do quite a bit more work). But the performance results do show just how good thepowerSet
algorithm is (and it is a reusable function). I've also filtered out the ambiguity, which slows things slightly.Javascript
Output
On jsFiddle
And added to the jsPerf
It looked like to much fun not to play, here's what I have.
Javascript
Output
On jsFiddle
And a jsPerf of all these, although @jcarpenter solutions gives an ambiguity.
On a modern browser you could squeeze more out of this solution using
for
intead ofwhile
as they are highly optimised forfor
. And assign by index rather thanpush
would also give you a performance boost.It would be nice to extend the performance tests to include some more test sets, maybe if I get bored.
I would say the problem here is to take the power set of an array, and filter it down to only the elements whose sum is greater than a certain number.
The power set of a set is the set of all subsets of that set. (Say that five times fast and you'll be a mathematician)
For example, the power set of
[1]
is[[], [1]]
and the power set of[1, 2]
is[[], [1], [2], [1, 2]]
.First I would define a
powerSet
function like this:Then I would define a function that takes the power set of the array and only includes elements whose sum is less than or equal to some amount:
This might not be fast on large arrays, but it works well for small ones.
It looks like it gives the right answer for
console.log(subsetsLessThan([1,3,6,10,-1], 9));
edit: a little more about the power set function as implemented here
The only subset of
[]
is[]
, so the power set of[]
is a set containing only[]
. That would be[[]]
.The initial
if
statement in thepowerSet
function immediately returns[[]]
if you pass in[]
.If you pass in a set with at least one element, the
powerSet
function begins by removing the last element. For example, if you callpowerSet
on[1, 2]
, the variablelastElement
will be set to2
andarr
will be set to[1]
.Then the
powerSet
function recursively calls itself to get the power set of the "rest" of the list. If you had passed in[1, 2]
, thenrestPowerset
is assigned topowerSet([1])
which is[[], [1]]
.We define a variable that's going to hold the power set of what was passed in, here
[1, 2]
We loop through every set in
restPowerset
.Any subset of
[1]
is also a subset of[1, 2]
so we add it to the list. That is,[]
and[1]
are both subsets of[1, 2]
.If you add the element
2
to any subset of[1]
, that is also a subset of[1, 2]
, so we add it to the list. Both[2]
and[1, 2]
are subsets of[1, 2]
.That's all. At this point, the variable
powerset
is[[], [2], [1], [1, 2]]
. Return it!Similar to Matt's answer, but uses Array.filter() and Array.reduce() to pack a punch. The variable,
mask
is incremented from 1 to 32-1 in this example (because array length is 5 andcount
= 1 << 5, which is 32). The array is filtered for each mask increment, producing a new array or permutation where only certain values are included.A value is included in the permutation if the mask shifted right by the value's index is odd. Think binary here, because either a value is supposed to be in the permutation or it isn't (0 or 1) and since the mask will go through all possible numbers, all of the possible permutations are covered directly in the number when expressed as binary:
The function,
indexVisible()
is used to filter the original array and return a permutation that matches the mask.The function,
sum()
is used to reduce each permutation to the sum of its values, and if that sum is less than or equal ton
then it is included in the final result and returned fromcombinations()
Here are the permutations:
[[1],[3],[1,3],[6],[1,6],[3,6],[1,3,6],[10],[1,10],[3,10],[1,3,10],[6,10],[1,6,10],[3,6,10],[1,3,6,10],[-1],[1,-1],[3,-1],[1,3,-1],[6,-1],[1,6,-1],[3,6,-1],[1,3,6,-1],[10,-1],[1,10,-1],[3,10,-1],[1,3,10,-1],[6,10,-1],[1,6,10,-1],[3,6,10,-1],[1,3,6,10,-1]]
Here are the results:
[[1],[3],[1,3],[6],[1,6],[3,6],[-1],[1,-1],[3,-1],[1,3,-1],[6,-1],[1,6,-1],[3,6,-1],[1,3,6,-1],[10,-1]]
You can see how all of this works and play with different combinations in this JSFiddle.
Brevity is very cryptic here. How about some descriptive functions?
The approach uses binary to create maps of all the possible combinations. Then the map is used to pluck items from the array. The plucked items are summed, and that's about it.
The result of
combinations([1, 3, 6, 10, -1], 9)
produced is:[[-1],[10,-1],[6],[6,-1],[3],[3,-1],[3,6],[3,6,-1],[1],[1,-1],[1,6],[1,6,-1],[1,3],[1,3,-1],[1,3,6,-1]]
.Here is a Fiddle.
The following code will give you all sub-arrays summing up to 9 or less..