hope someone can give me hints to solve my problem.
I have a given object with the following scheme:
{
"prop1": value1,
"prop2": value2,
"nested1": [{A},{B}],
"nested2": [{C},{D}],
"nested3": [{E},{F}],
}
what I want to get from my original object is the following:
{
items: [
{
"prop1": value1,
"prop2": value2,
"nested1": {A},
"nested2": {C},
"nested3": {E},
},
{
"prop1": value1,
"prop2": value2,
"nested1": {B},
"nested2": {D},
"nested3": {F},
},
]
}
the items.length is the same as the array length in original object's nested1, nested2 etc. properties (2 in this example).
I cannot find a solid way to refactor the original object using javascript native functions.
Any help is appreciated.
-
Do the arrays all have the same number of elements?Andreas– Andreas2020年08月03日 16:06:59 +00:00Commented Aug 3, 2020 at 16:06
-
yes, all nested arrays in original object have the same length.Vahe Karapetyan– Vahe Karapetyan2020年08月03日 18:03:44 +00:00Commented Aug 3, 2020 at 18:03
6 Answers 6
I modified your example slightly, and used strings, in order to have a valid Object. This would be one way of doing it:
const input = {
prop1: "value1",
prop2: "value2",
nested1: ["A","B"],
nested2: ["C","D"],
nested3: ["E","F"],
};
const output = new Array(input.nested1.length).fill().map((_, i) => ({
prop1: input.prop1,
prop2: input.prop2,
nested1: input.nested1[i],
nested2: input.nested2[i],
nested3: input.nested3[i]
}));
console.log(output);
1 Comment
Array.from({ length: input.nested1.length }).map((_, i) => ...)Use map and destructuring
const convert = ({ nested1, nested2, nested3, ...rest }) => ({
items: nested1.map((nested1, i) => ({
...rest,
nested1,
nested2: nested2[i],
nested3: nested3[i],
}))
});
const obj = {
prop1: 'value1',
prop2: 'value2',
nested1: [{ 'A': 'a' }, { 'B': 'b' }],
nested2: [{ 'C': 1 }, { 'D': 2 }],
nested3: [{ 'E': 5 }, { 'F': 6 }],
};
console.log(convert(obj));
Comments
If you are a beginner then you can achieve the above task simply like this.
const input = {
prop1: "value1",
prop2: "value2",
nested1: ["A","B"],
nested2: ["C","D"],
nested3: ["E","F"],
};
let arr1 ={
prop1:input.prop1,
prop2:input.prop2,
nested1:input.nested1[0],
nestend2:input.nested2[0],
nested3:input.nested3[0],
}
let arr2 ={
prop1:input.prop1,
prop2:input.prop2,
nested1:input.nested1[1],
nestend2:input.nested2[1],
nested3:input.nested3[1],
}
console.log({items:[arr1,arr2]});
Comments
A generic solution for arbitrary cases
function buildItems(obj) {
const commonPairs = Object.entries(obj).reduce(
(accumulate, [key, val]) =>
Array.isArray(val) ? accumulate : { ...accumulate, [key]: val },
{}
)
const arrayPairs = Object.entries(obj).reduce(
(accumulate, [key, val]) =>
!Array.isArray(val) ? accumulate : { ...accumulate, [key]: val },
{}
)
if (Object.keys(arrayPairs).length === 0) {
return [{ ...commonPairs }]
}
const res = []
for (let i = 0; i < arrayPairs[Object.keys(arrayPairs)[0]].length; i++) {
res.push({
...commonPairs,
...Object.keys(arrayPairs).reduce(
(acc, key) => ({ ...acc, [key]: arrayPairs[key][i] }),
{}
),
})
}
return res
}
console.log(
"1)",
buildItems({
prop1: "value1",
prop2: "value2",
nested1: [{ A: 1 }, { B: 1 }, { G: 1 }],
nested2: [{ C: 1 }, { D: 1 }, { H: 1 }],
nested3: [{ E: 1 }, { F: 1 }, { I: 1 }],
nested4: [{ J: 1 }, { K: 1 }, { L: 1 }],
nested5: [{ M: 1 }, { N: 1 }, { O: 1 }],
}),
"\n"
)
console.log(
"2)",
buildItems({
prop1: "value1",
prop2: "value2",
}),
"\n"
)
console.log(
"3)",
buildItems({
prop1: "value1",
prop2: "value2",
nested1: [{ A: 1 }, { B: 1 }, { G: 1 }],
}),
"\n"
)
Comments
You use Array.from with a mapping callback.
const obj = {
"prop1": 'value1',
"prop2": 'value2',
"nested1": ['A','B'],
"nested2": ['C','D'],
"nested3": ['E','F'],
};
const res = {items: Array.from({length: obj.nested1.length}, (_,i)=>({
prop1: obj.prop1, prop2: obj.prop2,
nested1: obj.nested1[i],
nested2: obj.nested2[i],
nested3: obj.nested3[i]
}))};
console.log(res);
You could also map over any of the nested arrays.
const obj = {
"prop1": 'value1',
"prop2": 'value2',
"nested1": ['A','B'],
"nested2": ['C','D'],
"nested3": ['E','F'],
};
const res = {
items: obj.nested1.map((nested1,i)=>({
prop1: obj.prop1, prop2: obj.prop2,
nested1, nested2: obj.nested2[i], nested3: obj.nested3[i]
}))
}
console.log(res);
Comments
Here's a fully generic solution, you don't need to know the names of the properties, not even any name of the property containing the array. This works for any amount of properties, as long as the structure is similar to the example in the question.
const source = {
"prop1": 'value1',
"prop2": 'value2',
"nested1": [{A: 1}, {B: 2}],
"nested2": [{C: 2}, {D: 4}],
"nested3": [{E: 5}, {F: 6}]
},
items = [];
let len = 0;
// Get the length of the nested arrays
for (const [key, value] of Object.entries(source)) {
if (Array.isArray(value)) {
len = value.length;
break;
}
}
// Create item array objects
for (let n = 0; n < len; n++) {
items.push({});
for (const [key, value] of Object.entries(source)) {
items[n][key] = (Array.isArray(value)) ? value[n] : value;
}
}
console.log(items);
At first the code simply searches for the first array, and then stores the length of the found array. After found the length, the new objects and their properties are pushed to items array. Whether the value is directly the property value, or taken from the array, is determined by the type of the property.
Comments
Explore related questions
See similar questions with these tags.