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 and count
= 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:
- index: 4,3,2,1,0
- mask: 0 0 0 0 1 (grab index 0, [1])
- mask: 0 0 0 1 0 (grab index 1, [3])
- mask: 0 0 0 1 1 (grab index 0 and 1, [1,3])
- mask: 1 1 0 0 0 (grab index 3 and 4, [10,-1])
var a = [1,3,6,10,-1];
function combinations(array, n) {
var mask, len = array.length, count = 1 << len, permutations = [];
var indexVisible = function(v, i) { return ((mask >> i) & 1) == 1 }
var sum = function(a, b) { return a + b }
for (mask = 1; mask < count; ++mask) {
permutations.push(array.filter(indexVisible))
}
return permutations.filter(function(p) { return p.reduce(sum) <= n })
}
console.log(JSON.stringify(combinations(a, 9)));
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 to n
then it is included in the final result and returned from combinations()
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.