This is my array of objects
[{
"key1": "value1",
"key2": "value2",
"key3": ["value3", "value4"]
}]
The result should be like this
[{
"key1": "value1",
"key2": "value2",
"key3": "value3"
}, {
"key1": "value1",
"key2": "value2",
"key3": "value4"
}]
So I want to get rid of the sub array in property key3
and get the new equivalent structure, copying all the other properties.
For reasons I cannot change I am supposed to use lodash, but only in version 2.4.2
EDIT: To be more elaborate: I am using a JSON based form engine which allows to use existing functions (like lodash functions) but doesn't allow to define new functions. I also cannot use control structures like for loops. Essentially I can only use chained basic function calls including lodash.
I tried to use map, but map cannot extend an array, it can only convert one array element into something different
Is there any lodash magic I can use here?
EDIT2: Here is an example about what I mean when I say "I cannot introduce new functions". It will check if an array of objects is unique regarding a certain subset of properties
model = [{
"key1": "value1",
"key2": "value2",
"key3": "valuex"
},{
"key1": "value1",
"key2": "value2",
"key3": "valuey"
}]
// will give false because the two objects are not unique regarding the combination of "key1" and "key2"
_.uniq(model.map(_.partialRight(_.pick, ["key1", "key2"])).map(JSON.stringify)).length === model.length
Well, this was a challenge! I have a working solution that covers all the cases I can think of, but please let me know if there is a situation I missed.
My general approach started from the end, I knew I was going to use _.zipObject
to create the result objects. From there, it was just a matter of making the other properties line up with the necessary key3
values. To do so, I simply copy the property values so each value of key3
has its own copy. Next, I link them back up and create the objects. Finally, I filter out any unnecessary copies of the objects.
NOTE: This approach will not work correctly for an undefined
element in key3
. I considered this to be an unlikely situation, thus did not attempt to address.
The understandable version:
const objects = [{
"key1": "value1",
"key2": "value2",
"key3": ["value3", "value4"]
},
{
"key1": "value5",
"key2": "value6",
"key3": ["value7"]
}];
// Get other key names
const otherKeys = _.without(_.keys(objects[0]), "key3");
// Get values without key3
const otherValues = _.map(_.map(objects, _.partialRight(_.omit, "key3")), _.values);
// Get just key3 values
const onlyKey3 = _.map(objects, "key3");
// Generate dummy range of needed length
const maxLengthKey3 = _.max(_.map(onlyKey3, "length"));
const dummyRange = _.range(maxLengthKey3);
// Grow all arrays to needed length
const newOtherValues = _.flatten(_.map(dummyRange, _.partial(_.identity, otherValues)), true);
const newKey3 = _.flatten(_.map(dummyRange, _.partial(_.map, onlyKey3)));
const pairedValues = _.map(_.zip(newOtherValues, newKey3), _.flatten);
const resultObjects = _.map(pairedValues, _.partial(_.zipObject, _.union(otherKeys, ["key3"])));
// Filter out unnecessary objects
const result = _.filter(resultObjects, "key3");
All in one line:
const objects = [{
"key1": "value1",
"key2": "value2",
"key3": ["value3", "value4"]
},
{
"key1": "value5",
"key2": "value6",
"key3": ["value7"]
}];
// One line
const result = _.filter(_.map(_.map(_.zip(_.flatten(_.map(_.range(_.max(_.map(_.map(objects, "key3"), "length"))), _.partial(_.identity, _.map(_.map(objects, _.partialRight(_.omit, "key3")), _.values))), true), _.flatten(_.map(_.range(_.max(_.map(_.map(objects, "key3"), "length"))), _.partial(_.map, _.map(objects, "key3"))))), _.flatten), _.partial(_.zipObject, _.union(_.without(_.keys(objects[0]), "key3"), ["key3"]))), "key3");
Performance:
I expect it to be terrible for a large initial array, or for a large length key3
. I especially shudder at the single line version. If anyone complains, I'd make the point that this is caused by the limitations of the execution environment.
This was tested in the browser via https://npm.runkit.com/lodash, using var _ = require('[email protected]');
let obj = {
key1: "value1",
key2: "value2",
key3: ["value3", "value4"]
}
let tracker = new Array(obj.key3.length)
let newObjArr = []
for (let i = 0; i < tracker.length; i++) {
newObjArr.push({
key1: obj.key1,
key2: obj.key2,
key3: obj.key3[i]
})
}
console.log(newObjArr)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With