import _ from 'lodash';
import '../../globals.js';
// Copyright 2022, University of Colorado Boulder
/**
 * An immutable combination that represents a subset of a set
 *
 * @author Jonathan Olson <jonathan.olson@colorado.edu>
 */
import dot from './dot.js';
class Combination {
    /**
     * Creates a combination that will include elements where list[i] === true
     */
    constructor(inclusions) {
        this.inclusions = inclusions;
    }
    size() {
        return this.inclusions.length;
    }
    includes(index) {
        return this.inclusions[index];
    }
    /**
     * Applies the combination to an array, returning a new array with the used elements.
     */
    apply(array) {
        return array.filter((element, index) => this.inclusions[index]);
    }
    /**
     * Creates a new combination that is the inverse of this (includes the opposite elements)
     */
    inverted() {
        return new Combination(this.inclusions.map(inclusion => !inclusion));
    }
    getIncludedIndices() {
        return _.range(0, this.size()).filter(i => this.inclusions[i]);
    }
    toString() {
        return `C[${this.inclusions.map(i => i ? '1' : '0').join('')}]`;
    }
    equals(combination) {
        return this.inclusions.length === combination.inclusions.length && _.isEqual(this.inclusions, combination.inclusions);
    }
    /**
     * Creates an empty combination of a given size.
     */
    static empty(size) {
        return new Combination(_.range(0, size).map(() => false));
    }
    /**
     * Creates a full combination of a given size.
     */
    static full(size) {
        return new Combination(_.range(0, size).map(() => true));
    }
    /**
     * Lists all combinations from a given size
     */
    static combinations(size) {
        const combinations = [];
        const stack = [];
        (function recurse(index) {
            if (index === size) {
                combinations.push(new Combination(stack.slice()));
            }
            else {
                stack.push(false);
                recurse(index + 1);
                stack.pop();
                stack.push(true);
                recurse(index + 1);
                stack.pop();
            }
        })(0);
        return combinations;
    }
    /**
     * Calls a callback on every single possible permutation of the given Array
     *
     * @param array
     * @param callback - Called on each permuted version of the array possible
     */
    static forEachCombination(array, callback) {
        const stack = [];
        (function recurse(index) {
            if (index === array.length) {
                callback(stack);
            }
            else {
                recurse(index + 1);
                stack.push(array[index]);
                recurse(index + 1);
                stack.pop();
            }
        })(0);
    }
    static combinationsOf(array) {
        const results = [];
        Combination.forEachCombination(array, result => {
            results.push(result.slice());
        });
        return results;
    }
}
dot.register('Combination', Combination);
export default Combination;
//# sourceMappingURL=Combination.js.map