| 447 | // Generates all subsets of size subsetSize which contain the indices already |
| 448 | // in chosenIndices (and no indices that are "less than" any of them). |
| 449 | var generateSubsetsOfFixedSize = function (goalSize, chosenIndices) { |
| 450 | // If we've found a subset of the size we're looking for, output it. |
| 451 | if (chosenIndices.length === goalSize) { |
| 452 | // Change from indices into the actual elements. Note that 'elements' is |
| 453 | // a newly allocated array which cb may mutate or retain. |
| 454 | var elements = []; |
| 455 | _.each(chosenIndices, function (index) { |
| 456 | elements.push(total[index]); |
| 457 | }); |
| 458 | if (cb(elements)) { |
| 459 | throw new Done(); // unwind all the recursion |
| 460 | } |
| 461 | return; |
| 462 | } |
| 463 | |
| 464 | // Otherwise try adding another index and call this recursively. We're |
| 465 | // trying to produce a sorted list of indices, so if there are already |
| 466 | // indices, we start with the one after the biggest one we already have. |
| 467 | var firstIndexToConsider = chosenIndices.length ? |
| 468 | chosenIndices[chosenIndices.length - 1] + 1 : 0; |
| 469 | for (var i = firstIndexToConsider; i < total.length; ++i) { |
| 470 | var withThisChoice = _.clone(chosenIndices); |
| 471 | withThisChoice.push(i); |
| 472 | generateSubsetsOfFixedSize(goalSize, withThisChoice); |
| 473 | } |
| 474 | }; |
| 475 | |
| 476 | try { |
| 477 | for (var goalSize = 0; goalSize <= total.length; ++goalSize) { |