Reputation: 2262
I have the following array of arrays
let arr = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ],
]
I'd like to achieve this structure
let foo = [
{
value: "Female",
children: [
{
value: "Dinner",
children: [
{
value: "No"
},
{
value: "Yes"
},
]
},
{
value: "Lunch",
children: [
{
value: "No"
},
{
value: "Yes"
},
]
},
]
},
{
value: "Male",
children: [
{
value: "Dinner",
children: [
{
value: "No"
},
{
value: "Yes"
},
]
},
{
value: "Lunch",
children: [
{
value: "No"
},
{
value: "Yes"
},
]
},
]
},
]
I simply can't wrap my head around the problem to achieve this, thus, I don't have a starting code to post, so please if you can help, it would be great.
Upvotes: 0
Views: 954
Reputation: 172
Rearrange your Array using the below code, then iterate as your wish and this is dynamic. you can have more rows in arr variable.
let arr = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ],
]
for(let i=arr.length-2; i>-1; i--){
for(let j=0; j< arr[i].length; j++) {
item = {}
item[arr[i][j]] = arr[i+1];
arr[i][j] = [];
arr[i][j] = item;
}
arr.pop();
}
console.log(arr);
/*output*/
[
[{
'Female': [{
'Dinner': ['No', 'Yes']
}, {
'Lunch': ['No', 'Yes']
}]
}, {
'Male': [{
'Dinner': ['No', 'Yes']
}, {
'Lunch': ['No', 'Yes']
}]
}]
]
https://jsfiddle.net/Frangly/ywsL0pbt/149/
Upvotes: 2
Reputation: 135197
recursion
Recursion is a functional heritage and so using it with functional style yields the best results. This means avoiding things like mutation, variable reassignments, and other side effects.
We can write make(t)
using inductive inductive reasoning -
t
is empty, return the empty result []
t
has at least one element. For all value
in the first element t[0]
, return a new object {value, children}
where children
is the result of the recursive sub-problem make(t.slice(1))
const make = t =>
t.length == 0
? [] // 1
: t[0].map(value => ({ value, children: make(t.slice(1)) })) // 2
const myinput = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ]
]
console.log(make(myinput))
Above we write make
as a single pure functional expression using ?:
. This is equivalent to an imperative style if..else
-
function make(t) {
if (t.length == 0)
return []
else
return t[0].map(value => ({ value, children: make(t.slice(1)) }))
}
const myinput = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ]
]
console.log(make(myinput))
visualize
It helps for us to visualize how these work
make([[ "Female" , "Male" ], [ "Dinner" , "Lunch" ], [ "No" , "Yes" ]])
= [
{value: "Female", children: make([[ "Dinner" , "Lunch" ], [ "No" , "Yes" ]]) },
{value: "Male", children: make([[ "Dinner" , "Lunch" ], [ "No" , "Yes" ]]) }
]
make([[ "Dinner" , "Lunch" ], [ "No" , "Yes" ]])
= [
{value: "Dinner", children: make([[ "No" , "Yes" ]]) },
{value: "Lunch", children: make([[ "No" , "Yes" ]]) }
}
make([[ "No" , "Yes" ]])
= [
{value: "No", children: make([]) },
{value: "Yes", children: make([]) }
}
make([])
= []
remove empty children
Now that we see how it works, we prevent making empty children: []
properties by adding one more conditional. When t
has just one element, simply create a {value}
for all value
in the element -
function make(t) {
switch (t.length) {
case 0:
return []
case 1:
return t[0].map(value => ({ value }))
default:
return t[0].map(value => ({ value, children: make(t.slice(1)) }))
}
}
const myinput = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ]
]
console.log(make(myinput))
Which produces the output you are looking for -
[
{
"value": "Female",
"children": [
{
"value": "Dinner",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
},
{
"value": "Lunch",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
}
]
},
{
"value": "Male",
"children": [
{
"value": "Dinner",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
},
{
"value": "Lunch",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
}
]
}
]
Upvotes: 4
Reputation: 59
Checkout this code snippet. It outputs as per your need.
let arr = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ],
]
let foo = [];
let arr2 = [];
arr[2].forEach(yn => {
arr2.push({ "value": yn});
});
let arr1 = [];
arr[1].forEach(dl => {
arr1.push({
"value": dl,
"children": arr2
});
});
arr[0].forEach(fm => {
foo.push({
"value": fm,
"children": arr1
});
});
console.log(JSON.stringify(foo, null, 2))
Upvotes: -1
Reputation: 1198
You can try this:
let arr = [
['Female', 'Male'],
['Dinner', 'Lunch'],
['No', 'Yes']
]
function makeTree(a, ch = [], currIndex = 0) {
for (const item of a[currIndex]) {
if (a[currIndex + 1]) {
// If there is an array after this one then
// include the 'children' array
const obj = { value: item, children: [] }
ch.push(obj)
// Run the function again to fill the `children`
// array with the values of the next array
makeTree(a, obj.children, currIndex + 1)
} else {
// If this is the last array then
// just include the value
ch.push({ value: item })
}
}
return ch
}
const result = makeTree(arr)
console.log(JSON.stringify(result, null, 2))
.as-console-wrapper { min-height: 100% }
Upvotes: 1
Reputation: 2505
You can also do it without recursion with 2 for
let arr = [
[ "Female" , "Male" ],
[ "Dinner" , "Lunch" ],
[ "No" , "Yes" ],
];
var lastChild = -1;
for(var i = arr.length-1; i >= 0; i--) {
var item = arr[i];
var lastChildTemp = [];
for(var j = 0; j < item.length; j++) {
var newChild = {value: item[j]};
if(lastChild != -1) {
newChild.children = lastChild;
}
lastChildTemp.push(newChild);
}
lastChild = lastChildTemp;
}
console.log(JSON.stringify(lastChildTemp,null,2));
Output:
[
{
"value": "Female",
"children": [
{
"value": "Dinner",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
},
{
"value": "Lunch",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
}
]
},
{
"value": "Male",
"children": [
{
"value": "Dinner",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
},
{
"value": "Lunch",
"children": [
{
"value": "No"
},
{
"value": "Yes"
}
]
}
]
}
]
The key here is to use backward for (starting from high index to low index), then create a lastChild
object. Then put it in .children
attribute of each next objects.
Upvotes: 2