maxedison
maxedison

Reputation: 17573

All combinations of of an object with array values for its keys

I'm essentially looking for the JavaScript equivalent of this answer, specifically in the first format provided in that response.

In other words, given the object:

let variants = {
  debug : ["on", "off"],
  locale : ["de_DE", "en_US", "fr_FR"],
}

I'd like a function that returns:

[{debug: 'on', locale: 'de_DE'},
 {debug: 'on', locale: 'en_US'},
 {debug: 'on', locale: 'fr_FR'},
 {debug: 'off', locale: 'de_DE'},
 {debug: 'off', locale: 'en_US'},
 {debug: 'off', locale: 'fr_FR'}]

The solution I'm looking for should be unaware of what keys are in the input object.

Upvotes: 3

Views: 1779

Answers (2)

trincot
trincot

Reputation: 351369

You could use this ES6 function:

function combinations(variants) {
    return (function recurse(keys) {
        if (!keys.length) return [{}];
        let result = recurse(keys.slice(1));
        return variants[keys[0]].reduce( (acc, value) =>
            acc.concat( result.map( item => 
                Object.assign({}, item, { [keys[0]]: value }) 
            ) ),
            []
        );
    })(Object.keys(variants));
}                     

// Sample data
let variants = {
  debug : ["on", "off"],
  locale : ["de_DE", "en_US", "fr_FR"],
};
// Result
console.log(combinations(variants));

Explanation

The main function gets the array of keys (with Object.keys) of the given object, and passes it to a recursive function (recurse).

This inner function first checks if there are keys, if not the recursion ends, and an array with a single, empty object is returned.

In all other cases, the function is called recursively with one less key.

The result from that recursive call is then iterated (with result.map()) and for each entry, a new object is generated that has one more property -- the current key (i.e. the first from the array of keys) and the current value for that key. The values are iterated over with reduce(), and the above is repeated for every such value. These sub-results are concatenated with acc.concat() into a larger array that is returned to the caller.

Upvotes: 5

Patrick Barr
Patrick Barr

Reputation: 1123

var debugCombs = [];
for(var debugVal in debug) {
    for(var localeVal in locale) {
         debugCombs.push({debug: debugVal, locale: localeVal});
    }
}

I hope this is fairly self explanatory: iterate through each list and push it all to an array.

Upvotes: 1

Related Questions