AJ Hurst - 1 year ago 108
Javascript Question

# Using underscore to get all keys and list of unique values for each

Starting with an array of objects, I need get a list of all keys and all the unique values for each. The problem is that I don't know the keys beforehand. There are plenty of solutions if you know the key, but in this case each object can have any number of keys and each key has an array of values. The code below works, but it's quite complicated and there must be a simpler solution.

Input:

``````[
{
key_1: [ attribute_value_1, attribute_value_2, ... ],
key_2: [ attribute_value_3, attribute_value_4, ... ],
},
...
]
``````

Output:

``````[
{
label: key_1,
options: [ attribute_value_1, attribute_value_2, ... ]
},
{
label: key_2,
options: [ attribute_value_3, attribute_value_4, ... ]
},
...
]
``````

Suggested Solution:

``````    _.chain(input)
.map(function (attr) {
return _.keys(attr).map(function (key) {
return {
key: key,
value: attr[key]
};
});
})
.flatten()
.groupBy('key')
.map(function (grouped_values, key) {
// value = array of { key, value }
return {
label: key,
options: _.chain(grouped_values)
.pluck('value')
.flatten()
.uniq()
.value()
};
})
.value();
``````

Using lodash - Apply `_.mergeWith()` to the input array, and use the customizer function to combine the arrays and get the unique values. Afterwards `_.map()` the result to the required format:

``````var input = [
{
key_1: [ "attribute_value_1", "attribute_value_2" ],
key_2: [ "attribute_value_3", "attribute_value_4" ]
},
{
key_1: [ "attribute_value_1", "attribute_value_5" ],
key_2: [ "attribute_value_2", "attribute_value_3" ],
key_5: [ "attribute_value_2", "attribute_value_3" ]
}
];

var params = [{}].concat(input).concat(function (objValue, srcValue) { // create the params to apply to mergeWith
if (_.isArray(objValue)) {
return _.union(objValue, srcValue); // merge the arrays, and get the unique values
}
});

var result = _.map(_.mergeWith.apply(_, params), function(value, key) { // merge all objects in the array, and map the results to required format
return {
label: key,
options: value
};
});

console.log(result);``````
``<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.min.js"></script>``

And you can clean up the ugly `params` array if you use ES6:

``````const input = [
{
key_1: [ "attribute_value_1", "attribute_value_2" ],
key_2: [ "attribute_value_3", "attribute_value_4" ]
},
{
key_1: [ "attribute_value_1", "attribute_value_5" ],
key_2: [ "attribute_value_2", "attribute_value_3" ],
key_5: [ "attribute_value_2", "attribute_value_3" ]
}
];

const customizer = (objValue, srcValue) => {
if (_.isArray(objValue)) {
return _.union(objValue, srcValue); // merge the arrays, and get the unique values
}
};

const result = _.map(_.mergeWith({}, ...input, customizer), (value, key) => ({ // merge all objects in the array, and map the results to required format
label: key,
options: value
}));

console.log(result);``````
``<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.min.js"></script>``

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download