I was using react-tree-graph and I was creating a data object but I want to use my backend api to fill in the properties of the data object. I tried using the .map method to loop through my api but I couldnt figure out how to get it to work. Here's the data object and below is my object from my api.
let data = {
name: 'Water',
children: [
{
name: 'Earth',
children: [
{
name: 'Air',
children: [
{
name: 'Fire',
children: [],
},
{
name: 'Fire2',
children: [],
},
],
},
{
name: 'Air2',
children: [
{
name: 'Fire3',
children: [],
},
{
name: 'Fire4',
children: [],
},
],
},
],
},
{
name: 'Earth2',
children: [
{
name: 'Air3',
children: [
{
name: 'Fire5',
children: [],
},
{
name: 'Fire6',
children: [],
},
],
},
{
name: 'Air4',
children: [
{
name: 'Fire7',
children: [],
},
{
name: 'Fire8',
children: [],
},
],
},
],
},
],
};
Instead of the strings I want to map through this variable and fill it in with object as such
flower= {water: "name1",air: "name2",air2: "name3",air3: "name4",air4: "name5",earth: "name6",earth2: "name7",fire: "name8",fire2: "name9",fire3: "name10",fire4: "name11",fire5: "name12",fire6: "name13",fire7: "name14",fire8: "name15"}
I just wanted to know how I could use this object and map through it to fill in the different properties inside the data object
Here is a solution for you question, Ive worked with recursive.
let data = {
name: 'Water',
children: [
{
name: 'Earth',
children: [
{
name: 'Air',
children: [
{
name: 'Fire',
children: [],
},
{
name: 'Fire2',
children: [],
},
],
},
{
name: 'Air2',
children: [
{
name: 'Fire3',
children: [],
},
{
name: 'Fire4',
children: [],
},
],
},
],
},
{
name: 'Earth2',
children: [
{
name: 'Air3',
children: [
{
name: 'Fire5',
children: [],
},
{
name: 'Fire6',
children: [],
},
],
},
{
name: 'Air4',
children: [
{
name: 'Fire7',
children: [],
},
{
name: 'Fire8',
children: [],
},
],
},
],
},
],
};
let counter = 1;
function recursiveNaming(data) {
return data.children.reduce((acc, curr) => {
let obj;
let currentObj = {...acc, [curr.name]:`name${counter++}`};
if(curr.children.length) {
obj = recursiveNaming(curr);
}
return {...currentObj, ...obj };
},{})
};
console.log(recursiveNaming(data))
Hope it worth it....
Related
Looking for a javascript or typescript solution to turn this array of sql data into a tree structure:
Some other solutions I've tried set the id as a property in the expected array but not the key of the object like in the expected solution.
const sqlData = [
{ id: 1, label: 'root', parentId: 0 },
{ id: 2, label: 'ant', parentId: 1 },
{ id: 3, label: 'cat', parentId: 1 },
{ id: 4, label: 'bear', parentId: 3 },
{ id: 5, label: 'dog', parentId: 3 },
{ id: 6, label: 'elephant', parentId: 5 },
{ id: 7, label: 'frog', parentId: 1 },
];
const expected = [
{
1: {
label: 'root',
children: [
{
2: {
label: 'ant',
children: [],
},
},
{
3: {
label: 'cat',
children: [
{
4: {
label: 'cat',
children: [],
},
},
{
5: {
label: 'dog',
children: [
{
6: {
label: 'elephant',
children: [],
},
},
],
},
},
],
},
},
{
7: {
label: 'frog',
children: [],
},
},
],
},
},
];
This can be done with O(n) time complexity by leveraging object references. By creating a children array on each element and then adding the correct child to its parent's children array, you can accomplish building the whole tree.
const sqlData=[{id:1,label:"root",parentId:0},{id:2,label:"ant",parentId:1},{id:3,label:"cat",parentId:1},{id:4,label:"bear",parentId:3},{id:5,label:"dog",parentId:3},{id:6,label:"elephant",parentId:5},{id:7,label:"frog",parentId:1}];
const parentMap = {};
const root = [];
// Map parent positions
sqlData.forEach((el, i) => {
parentMap[el.id] = i;
el.children = [];
});
sqlData.forEach(({ id, parentId, label, children }) => {
const insert = { [id]: { label, children } };
if (parentId === 0) {
root.push(insert);
return;
}
sqlData[parentMap[parentId]].children.push(insert);
});
console.log(root);
I'm new with rxjs and i can't see how can i do what i need. I need to add a pair active:true recursively.
I have this data structure coming from api as observable:
var data = [
{
name: "hom",
subcategories: [
{ name: "reb" },
{ name: "nov" },
{ name: "otr" }
]
},
{
name: "muj",
subcategories: [
{ name: "REB" },
{ name: "NOV" },
{ name: "OT" }
]
},
{
name: "ni",
subcategories: [
{ name: "REB", subcategories: [
{name: "rebanis"},
{name: "rebawos"}] },
{ name: "NOV", subcategories: [
{name: "novebanis"},
{name: "novrebawos"}] },
{ name: "OT", subcategories: [
{name: "otrebanis"},
{name: "otrebawos"}]
}
]
}
];
And what i want is to add a active:true on every level that have subcategories, and i don't know how many nested subcategories could be.
This is the result that i want:
var data = [
{
active: true,
name: "hom",
subcategories: [
{ name: "reb" },
{ name: "nov" },
{ name: "otr" }
]
},
{
active: true,
name: "muj",
subcategories: [
{ name: "REB" },
{ name: "NOV" },
{ name: "OT" }
]
},
{
name: "ni",
active: true,
subcategories: [
{ name: "REB", active: true, subcategories: [
{name: "rebanis"},
{name: "rebawos"}] },
{ name: "NOV", active: true, subcategories: [
{name: "novebanis"},
{name: "novrebawos"}] },
{ name: "OT", active: true, subcategories: [
{name: "otrebanis"},
{name: "otrebawos"}]
}
]
}
];
I tried something like this:
const req = of(data)
.pipe(
map(data => {
const transformedData = Object.keys(data).map(key =>
Object.assign(data[key], { active: true })
);
return transformedData;
})
)
.subscribe(output => console.log(output));
But the result is not clear and it only affects on first level not on nested.
You can use map inside recursive function:
const data = [ { name: "hom", subcategories: [ { name: "reb" }, { name: "nov" }, { name: "otr" } ] }, { name: "muj", subcategories: [ { name: "REB" }, { name: "NOV" }, { name: "OT" } ] }, { name: "ni", subcategories: [ { name: "REB", subcategories: [ {name: "rebanis"}, {name: "rebawos"}] }, { name: "NOV", subcategories: [ {name: "novebanis"}, {name: "novrebawos"}] }, { name: "OT", subcategories: [ {name: "otrebanis"}, {name: "otrebawos"}] } ] } ];
const addNewProp=data=>data.map(o=>o.subcategories ? ({...o, active:true, subcategories: addNewProp(o.subcategories)}) : o);
console.log(addNewProp(data));
The question has nothing to do with rxJs and Observable, it is a problem of transformation of an Array.
I would try something like this
data.map(el => {
if(el.subcategories && el.subcategories.lenght > 0) {
const newEl = {...el};
newEl.active = true;
return newEl;
}
return {...el}
})
Notice that here I am using some sort of immutability and hence I create new elements within the loop. If this is not required in your case, you can simplify the code like this
data.map(el => {
if(el.subcategories && el.subcategories.lenght > 0) {
el.active = true;
}
return el
})
i Have enteried JS object like this:
const arr = [
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: [
{
name: 'obj-1-child1-child1-child1'
},
{
name: 'obj-1-child1-child1-child2'
}
]
},
{
name: 'obj-1-child1-child2'
}
]
},
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child2-child1',
children: [
{
name: 'obj-1-child2-child1-child1'
}
]
}
]
}
]
},
{
name: 'obj-2',
children: [
{
name: 'obj-2-child1',
children: [
{
name: 'obj-2-child1-child1'
}
]
}
]
}
]
I tried to do it by iterating the object with a FOR loop.
A separate object is needed for each step of this tree. obj1->child1 then obj1->child1->child1 then obj1->child1->child1->child1 etc for each step for all elements in tree
const arr1 = [
{
name: 'obj-1',
children: [] // one object for 1 step in tree
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: []
}
]
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: []
}
]
}
]
},
{
name: 'obj-1',
children: [
{
name: 'obj-1-child1',
children: [
{
name: 'obj-1-child1-child1',
children: [
{
name: 'obj-1-child1-child1-child1'
}
]
}
]
}
]
}
]
which means for such a tree, the result should be: 12 elements
I want to keep the parent-child relationship of the tree node.
I have a JSON tree, like this
{
id: null,
children: [
{
id: 1,
children: [
{
id: 11,
children: [
{
id: 111
children: []
}
]
},
{
id: '12',
children: []
},
]
},
{
id: '2',
children: [
{
id: '21',
children: []
},
{
id: '22',
children: [
{
id: '221',
children: []
}
]
},
]
},
]
}
I want flat the tree, like this
[
{ id: 1, parent: null,},
{ id: 11, parent: 1, },
{ id: 111, parent: 11, },
{ id: 2, parent: null, },
{ id: 21, parent: 2, },
...
]
parent automatic generated
Is there any good way?
You could use flatMap method and create recursive function that will return 1D array as a result.
const data = {"id":null,"children":[{"id":1,"children":[{"id":11,"children":[{"id":111,"children":[]}]},{"id":"12","children":[]}]},{"id":"2","children":[{"id":"21","children":[]},{"id":"22","children":[{"id":"221","children":[]}]}]}]}
const flatten = (data, parent = null) =>
data.flatMap(({ id, children }) => ([
{ id, parent },
...flatten(children, id)
]))
const result = flatten(data.children);
console.log(result)
You could get the object and return an array of the flat children.
const
getFlat = ({ id, children = [] }) =>
children.flatMap(o => [{ id: o.id, parent: id }, ...getFlat(o)]);
var data = { id: null, children: [{ id: 1, children: [{ id: 11, children: [{ id: 111, children: [] }] }, { id: '12', children: [] }] }, { id: '2', children: [{ id: '21', children: [] }, { id: '22', children: [{ id: '221', children: [] }] }] }] },
flat = getFlat(data);
console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If compatbility with Internet Explorer is important, then the following approach which avoids the need for Array#flatMap might suit:
const input={id:null,children:[{id:'1',children:[{id:'11',children:[{id:'111',children:[]}]},{id:'12',children:[]}]},{id:'2',children:[{id:'21',children:[]},{id:'22',children:[{id:'221',children:[]}]}]}]};
const result = [];
// Define recursive function to walk through the data tree
// and produce a flat array of required data
const recurse = (item, parent) => {
// Only add item to result if it has valid id
if (item.id) {
result.push({
id: item.id,
parent: parent ? parent.id : null
});
}
// Iterate the children of this item, traversing and
// processing them in the same way
item.children.forEach(child => recurse(child, item))
}
recurse(input);
console.log(result);
You can use a simple recursion to achieve this
let data = {
id: 1,
name: 'a1',
children: [{
id: 2,
name: 'a2',
children: [{
id: 3,
name: 'b1',
children: []
},
{
id: 4,
name: 'b2',
children: []
}
]
}]
}
function flatten(data){
output = [];
return (function indentHandler(data, level, parent){
output.push({id: data['id'], parent: parent})
if (data['children'].length === 0){
return output;
}
level += 1;
data['children'].forEach(function(child){
return indentHandler(child, level, data.name);
});
return output;
})(data, 0, null);
}
flatten(data);
use recursion
var tree = {
id: null,
children: [{
id: 1,
children: [{
id: 11,
children: [{
id: 111,
children: []
}]
},
{
id: '12',
children: []
},
]
},
{
id: '2',
children: [{
id: '21',
children: []
},
{
id: '22',
children: [{
id: '221',
children: []
}]
},
]
}
]
};
var flat = [];
function flatArray(arr, parentId) {
arr.forEach(function(el) {
flat.push({
id: el.id,
parent: parentId || null
});
if (el.children)
flatArray(el.children, el.id);
});
}
flatArray(tree.children, 0)
console.log(flat);
How do I return a set of documents that has sub-arrays that matches common values. To better explain, consider the following data:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
The task is,
Get all the Categories with all the products containing a specific color code:
For example,
For ColorCode = 6,
Result should be:
[
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
For ColorCode = 4,
Result should be:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
}]
For ColorCode = 7,
Result should be an empty array:
[]
Thanks in advance.
You're looking for Array.prototype.filter.
// filter out categories that don't contain color code 4
categories.filter(function(category) {
return category.products.filter(containsColor(4)) > 0;
});
function containsColor(colorCode) {
return function(product) {
return product.ColorCode.indexOf(colorCode) >= 0;
};
}