How to iterate children from array in javascript? - javascript

i Have an array that could be :
arr1 = ["node1","children1","children1.1","children1.1.1"]
or it could be
arr2 = ["node1","children1"]
and I want to make it in this json format :
const data_arr1 = [{
title: "Node 1",
childNodes: [
{ title: "Childnode 1" ,
childNodes: [
{
title: "Childnode 1.1",
childNodes: [
{ title: "Childnode 1.1.1" }
]
}
]
}
]
}];
var data_arr2 = {title:"node1",childNodes:{title:"children1"}}
I have do like that but i can't have the right format in iterative way :
BuildJson = (items) => {
const elements = items.split(",");
let result = {};
var children = []
result["title"] = elements[0];
elements.shift()
if(elements.length>1) {
for(var i=0;i<elements.length;i++){
elements.map((el,idx)=> {
children.push({title:el})
})
}
result["ChildNodes"] = children
}
Please how can I fix this algorithm ?

I suggest you to use recursive function.
I made you an example:
const t = ["lvl1", "lvl2", "lvl3"];
const r = (array) => {
if (array.length === 1) {
return {
title: array[0]
};
}
if (array.length > 1) {
return {
title: array[0],
childNode: r(array.slice(1))
};
}
};
r(t);
r(t) returned the following JSON:
{
"title": "lvl1",
"childNode": {
"title": "lvl2",
"childNode": {
"title": "lvl3"
}
}
}

const arr1 = ["node1","children1","children1.1","children1.1.1"]
const createArray = (arr, i = 0) => {
const obj = {
title: arr[i]
};
if (i < arr.length - 1) {
obj.childNodes = createArray(arr, ++i);
}
return [obj];
}
const newArr = createArray(arr1);
console.log(newArr);

Related

React.js: How to find duplicates for properties in an array of object and put a progressive number on that field

I have an array of object and each object is for example :
const myArr=[{name:"john",id:1}{name:"john",id:2}{name:"mary",id:3}]
for the first 2 element for the property "name" I have the name "john" that is duplicate.
How can I modify the rendered names like that:
const myArr=[{name:"john (1 of 2)",id:1}{name:"john (2 of 2)",id:2}{name:"mary",id:3}]
Thanks in advance!
Reduce the input array into a map by name (i.e. group by name property), and map the array of values to the result array. If the group array has more than 1 element in it then sub-map the group to include the numbering. Flatten the overall result.
const myArr = [
{ name: "john", id: 1 },
{ name: "john", id: 2 },
{ name: "mary", id: 3 }
];
const res = Object.values(
myArr.reduce((groups, current) => {
if (!groups[current.name]) {
groups[current.name] = [];
}
groups[current.name].push(current);
return groups;
}, {})
).flatMap((value) => {
if (value.length > 1) {
return value.map((current, i, arr) => ({
...current,
name: `${current.name} (${i + 1} of ${arr.length})`
}));
}
return value;
});
console.log(res);
You can do use reduce(), filter(), and flat() and do this:
const myArr = [
{name:"john", id:1},
{name:"john", id:2},
{name:"mary", id:3}
]
const res = Object.values(myArr.reduce((acc, curr) => {
const total = myArr.filter(({ name }) => name === curr.name).length;
if(!acc[curr.name]) {
acc[curr.name] = [
{...curr}
]
} else {
const currentSize = acc[curr.name].length;
if(currentSize === 1) {
acc[curr.name][0].name = `${acc[curr.name][0].name} (1 of ${total})`
}
acc[curr.name].push({
...curr,
name: `${curr.name} (${currentSize + 1} of ${total})`
})
}
return acc;
}, {})).flat();
console.log(res);
const myArr = [{name:"john",id:1}, {name:"john",id:2}, {name:"mary",id:3}];
const namesArray = myArr.map(elem => elem.name);
const namesTraversed = [];
let currentCountOfName = 1;
let len = 0;
myArr.forEach(elem => {
len = namesArray.filter(name => name === elem.name).length;
if (len > 1) {
if (namesTraversed.includes(elem.name)) {
namesTraversed.push(elem.name);
currentCountOfName = namesTraversed.filter(name => name === elem.name).length;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
} else {
namesTraversed.push(elem.name);
currentCountOfName = 1;
elem.name = `${elem.name} (${currentCountOfName} of ${len})`;
}
}
});
console.log(myArr);
Check if this helps you
const myArr = [{
name: "john",
id: 1
}, {
name: "john",
id: 2
}, {
name: "mary",
id: 3
}]
// to keep a track of current copy index
let nameHash = {}
const newMyArr = myArr.map(ele => {
const noOccurence = myArr.filter(obj => obj.name ===ele.name).length;
if(noOccurence > 1){
// if there are multiple occurences get the current index. If undefined take 1 as first copy index.
let currentIndex = nameHash[ele.name] || 1;
const newObj = {
name: `${ele.name} (${currentIndex} of ${noOccurence})`,
id: ele.id
}
nameHash[ele.name] = currentIndex+ 1;
return newObj;
}
return ele;
})
console.log(newMyArr);

Merge array of arrays based sub array index as keys (NodeJS/Javascript)

How to write a code that would merge my list in the following way? Performance is important. I want to convert the following array:
"list": [
[
"marketing",
"page_sections",
"PageOne"
],
[
"marketing",
"page_sections",
"PageTwo"
],
[
"webapp",
"page",
"pageone"
],
[
"webapp",
"page",
"pagetwo"
],
To the following format:
[
{
name: "marketing",
path: "marketing/",
children: [
{
name: "page_sections",
path: "marketing/page_sections",
children: [
{
name: "pageOne",
path: "marketing/page_sections/pageOne",
children: []
},
{
name: "pageTwo",
path: "marketing/page_sections/pageTwo",
children: []
},
}
],
},
{
name: "webapp",
path: "webapp/"
children: [
{
name: "page",
path: "webapp/page/"
children: [
{
name: "pageone",
path: "webapp/page/pageone"
children: []
},
{
name: "pagetwo",
path: "webapp/page/pagetwo"
children: []
},
}
]
},
]
The first index of sub array is parent, second index is child of parent, third index is child of second index (and so on).
The shortest approach is to iterate the nested names and look for an object with the same name. If not exist, create a new object. Return the children array as new level.
This approach features Array#reduce for iterating the outer array of data and for all inner arrays.
const
data = [["marketing", "page_sections", "PageOne"], ["marketing", "page_sections", "PageTwo"], ["webapp", "page", "pageone"], ["webapp", "page", "pagetwo"]],
result = data.reduce((r, names) => {
names.reduce((level, name, i, values) => {
let temp = level.find(q => q.name === name),
path = values.slice(0, i + 1).join('/') + (i ? '' : '/');
if (!temp) level.push(temp = { name, path, children: [] });
return temp.children;
}, r);
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Looking at the source, and your expected result.
What I would do is loop the list, and then do another loop inside the list. Mix this with Array.find..
Eg..
const data = {list:[
["marketing","page_sections","PageOne"],
["marketing","page_sections","PageTwo"],
["webapp","page","pageone"],
["webapp","page","pagetwo"]]};
function makeTree(src) {
const root = [];
for (const s of src) {
let r = root;
let path = '';
for (const name of s) {
path += `${name}/`;
let f = r.find(k => k.name === name);
if (!f) r.push(f = {name, path, children: []});
r = f.children;
}
}
return root;
}
console.log(makeTree(data.list));
.as-console-wrapper {
min-height: 100%;
}
You can do the following,
list= [
[
"marketing",
"page_sections",
"PageOne"
],
[
"marketing",
"page_sections",
"PageTwo"
],
[
"webapp",
"page",
"pageone"
],
[
"webapp",
"page",
"pagetwo"
],
];
getChildrenItem = (arr) => {
if(arr.length === 1) {
return { name: arr[0], children: []};
} else {
return { name: arr.splice(0,1)[0], children: [getChildrenItem([...arr])]};
}
}
merge = (srcArr, newObj) => {
const {name, children} = newObj;
let index = srcArr.findIndex(item => item.name === name);
if( index> -1) {
children.forEach(item => merge(srcArr[index].children, item))
return ;
} else {
srcArr.push(newObj);
return;
}
}
allObj = [];
list.forEach(item => {
let tempObj = getChildrenItem([...item]);
merge(allObj, tempObj);
});
console.log(allObj);
If Performance is an issue, I think this is one of the best solutions.
let list = [
["marketing", "page_sections", "PageOne"],
["marketing", "page_sections", "PageTwo"],
["webapp", "page", "pageone"],
["webapp", "page", "pagetwo"],
];
const dt = {};
const pushToOBJ = (Object, name) => {
if (Object[name]) return Object[name];
Object[name] = {
name,
children: {},
};
return Object[name];
};
for (let i = 0; i < list.length; i++) {
let subArray = list[i];
let st = pushToOBJ(dt, subArray[0]);
for (let j = 1; j < subArray.length; j++) {
st = pushToOBJ(st.children, subArray[j]);
}
}
let result = [];
const convertObjToChildArray = (obj) => {
if (obj === {}) return [];
let arr = Object.values(obj);
for (let i = 0; i < arr.length; i++) {
arr[i].children = convertObjToChildArray(arr[i].children);
}
return arr;
};
result = convertObjToChildArray(dt);
console.log(result);
No Use of JS find function, which already has O(n) Complexity.

JavaScript: How to convert nested array of object to key-value pair objects

It can be duplicate question but i have tried a lot but i did not get expected result.Could some one help me.
I am getting an array in request body like :
[
{
"name":"array",
"book":[
{
"name":"name1",
"book":"book1"
},
{
"name":"name2",
"book":"book2"
}
]
},
{
"name":"name3",
"book":"book3"
}
]
And I need to convert the array of nested array to below format
{
array: [
{
name1: "book1"
},
{
name2: "book2"
}
],
name3: "book3"
}
Note:In some cases book can be array or string.
On my first attempt i have tried below code to convert it into single object but it doest not convert nested array to key value pair
const array=[
{
"name":"array",
"book":[
{
"name":"name1",
"book":"book1"
},
{
"name":"name2",
"book":"book2"
}
]
},
{
"name":"name3",
"book":"book3"
}
]
var result = {};
for (var i = 0; i < array.length; i++) {
result[array[i].name] = array[i].value;
}
console.log(result);
Response for the above code
{
array: [
{
name: "name1",
book: "book1"
},
{
name: "name2",
book: "book2"
}
],
name3: "book3"
}
EDITED
I have made little change in the Code from the Ahmed's answer and it worked
const res=[
{
"name":"array",
"book":[
{
"name":"name1",
"book":"book1"
},
{
"name":"name2",
"book":"book2"
}
]
},
{
"name":"name3",
"book":"book3"
}
]
const obj = {}
for(let i = 0 ; i < res.length; i++){
let name = res[i].name
if(Array.isArray(res[i]['book'])){
obj[name] = [];
for(let item in res[i]['book']){
let key = res[i]['book'][item]['name']
let value = res[i]['book'][item]['book']
let entry = {}
entry[key] = value
obj[name].push(entry)
}
}
else{
obj[res[i].name]=res[i].book;
}
}
console.log(obj);
The added snippet should solve your problem.
The problem in your code was Appropriate nesting you didn't access the wanted values and didn't handle all the cases Hence, The wrong output.
const res = [
{
"name":"array",
"book":[
{
"name":"name1",
"book":"book1"
},
{
"name":"name2",
"book":"book2"
}
]
},
{
"name":"name3",
"book":"book3"
}
]
const obj = {}
for(let i = 0 ; i < res.length; i++){
let name = res[i].name
if(Array.isArray(res[i]['book'])){
obj[name] = []
for(let item in res[i]['book']){
let key = res[i]['book'][item]['name']
let value = res[i]['book'][item]['book']
let entry = {}
entry[key] = value
obj[name].push(entry)
}
}
else{
obj[name] = res[i]['book']
}
}
for(let item in obj){
console.log(item)
console.log(obj[item])
}

How to concatenate object values with same id

I have an array:
let ar = [
{
uid:1,
flat_no: 1
},
{
uid:2,
flat_no: 2
},
{
uid:1,
flat_no:3
}
];
If uid are same then I want to remove duplicate uid and concatenate its flat_no. The output array should be like this:
[
{
uid:1,
flat_no: [1,3]
},
{
uid:2,
flat_no: 2
}
];
You can use a combination of Array.reduce and Array.find.
If you find an existing item in your accumulator array, just update it's flat_no property, otherwise push it to the accumulator array.
let arr = [
{
uid: 1,
flat_no: 1
},
{
uid: 2,
flat_no: 2
},
{
uid: 1,
flat_no: 3
}
]
arr = arr.reduce((arr, item) => {
const existing = arr.find(innerItem => innerItem.uid === item.uid)
if (existing) {
existing.flat_no = Array.isArray(existing.flat_no)
? existing.flat_no
: [existing.flat_no]
existing.flat_no.push(item.flat_no)
} else {
arr.push(item)
}
return arr
}, [])
console.log(arr)
You can iterate over your array and fill an object (used as a hashmap here).
Once done, you extract the values to get your result.
let hashResult = {}
ar.forEach(element => {
if (hashResult[element.uid] == undefined) {
hashResult[element.uid] = { uid: element.uid, flat_no: [] }
}
hashResult[element.uid].flat_no.push(element.flat_no)
})
let result = Object.values(hashResult)
console.log(new Date(), result)
You can do this in a concise way with a single Array.reduce and Object.values to match your desired output:
let data = [ { uid:1, flat_no: 1 }, { uid:2, flat_no: 2 }, { uid:1, flat_no:3 } ];
const result = data.reduce((r, {uid, flat_no}) => {
r[uid] ? r[uid].flat_no = [r[uid].flat_no, flat_no] : r[uid] = {uid, flat_no}
return r
}, {})
console.log(Object.values(result))
1)Reduce the initial array to an object which has uid as the key and the flat_no as the value.
2)Then run a map on the keys to convert it into an array of objects with uid and flat_no.
1) First Step Code
let ar = [{uid:1, flat_no: 1},{uid:2, flat_no: 2},{uid:1, flat_no:3}];
let outputObj = ar.reduce((outputObj,currObj,currIndex) => {
let {uid,flat_no} = currObj
if (outputObj[uid]) {
outputObj[uid].push(flat_no)
}
else {
outputObj[uid] = [flat_no]
}
return outputObj
},{})
2)
let finalOutput = Object.keys(outputObj).map(key =>
({uid:key,flat_no:outputObj[key]}))
console.log(finalOutput)

How to Group Array by Property and Reindex Result

I am trying to group items an array of items by a property and then reindex the result starting from 0.
The following function returns a grouped set of items.
groupItemBy(array, property) {
let hash = {},
props = property.split('.');
for (let i = 0; i < array.length; i++) {
let key = props.reduce( (acc, prop) => {
return acc && acc[prop];
}, array[i]);
if (!hash[key]) hash[key] = [];
hash[key].push(array[i]);
}
return hash;
}
The result is an array of arrays, and something like:
[{
"1193312":[
{
"description":"Item 1",
"number": "1193312"
}
],
"1193314":[
{
"itemDesc":"Item 2"},
"number": "1193314"
{
"description":"Item 3",
"number": "1193314"
}
],
etc...
}]
From here I'd like to map 1193312 to 0, and 1193314 to 1, etc.
I tried .filter(val => val) on the result, but that seemed to have no effect.
You need to use an intermediate key replacement:
function groupItemBy(array, property) {
let hash = {}
let props = property.split('.')
let keys = []
for (let i = 0; i < array.length; i++) {
let key = props.reduce((acc, prop) => {
return acc && acc[prop];
}, array[i]);
let subst = keys.indexOf(key)
if (subst === -1) {
keys.push(key)
subst = keys.length - 1
}
if (!hash[subst]) hash[subst] = [];
hash[subst].push(array[i]);
}
return hash;
}
[ https://jsfiddle.net/05t9141p/ ]
You could use map for the array part, and Object.values and reduce for the renumber part.
const data = [{
"1193312":[
{
"time":"2018-02-20",
"description":"Item 1",
"number": "1193312"
}
],
"1193314":[
{
"time":"2018-02-21",
"itemDesc":"Item 2",
"number": "1193314"
},{
"time":"2018-02-21",
"description":"Item 3",
"number": "1193314"
}
]
}];
const renumbered =
data.map((m) => Object.values(m).reduce((a,v,ix) => (a[ix] = v, a), {}));
console.log(renumbered);
var data = [{
"1193312":[
{
"description":"Item 1",
"number": "1193312"
}
],
"1193314":[
{
"itemDesc":"Item 2",
"number": "1193314"},
{
"description":"Item 3",
"number": "1193314"
}
]
}]
var newData = Object.keys(data[0]).map(function(key,index){
var newObj={};
newObj[index] = data[0][key];
return newObj;
});
console.log(newData);
If you can use ES6:
var arr = [{
"1193312":[
{
"time":"2018-02-20",
"description":"Item 1"
}
],
"1193314":[
{
"time":"2018-02-21",
"itemDesc":"Item 2"},
{
"time":"2018-02-21",
"description":"Item 3"
}
]
}];
var data = arr[0];
var res = Object.entries(data).map(([key, value]) => ({[key]: value}));
console.log(res);

Categories

Resources