I have an object with nested objects. In this object, each objects having two or more sub-objects. I want to get together all sub-objects into an array of data. How to do with JavaScript?
const category = {
id: 1,
title: "a",
level: 2,
__parent: {
id: 2,
title: "b",
level: 1,
__parent: {
id: 3,
title: "c",
level: 0,
}
}
};
The output I want is this:
[{
id: 1,
title: "a",
level: 2,
__parent: null
},
{
id: 2,
title: "b",
level: 1,
__parent: null
},
{
id: 3,
title: "c",
level: 0,
__parent:null
}]
Case 1: Using Recursion
You can make recursive function like this:
const category = {
id: 1,
title: "a",
level: 2,
__parent: {
id: 2,
title: "b",
level: 1,
__parent: {
id: 3,
title: "c",
level: 0,
}
}
};
const result = [];
function recursiveOuput(data){
let tempObj = {};
Object.keys(data).map((key, index) => {
if(typeof data[key] !== 'object'){
tempObj[key] = data[key];
if(!Object.keys(data).includes('__parent') && (index === Object.keys(data).length -1)){
tempObj['__parent'] = null;
result.push(tempObj);
}
}else{
tempObj['__parent'] = null;
result.push(tempObj);
recursiveOuput(data[key]);
}
})
return result;
};
console.log(recursiveOuput(category));
Case 2: Using While loop
const category = {
id: 1,
title: "a",
level: 2,
__parent: {
id: 2,
title: "b",
level: 1,
__parent: {
id: 3,
title: "c",
level: 0,
}
}
};
const result = [];
let parent = category;
while (parent) {
result.push({
id: parent.id,
level: parent.level,
title: parent.title,
__parent: null
})
parent = parent.__parent
};
console.log(result);
It Be some like this :
const myArray = []
const category = ...;
function foo(obj){
myArray.push({
title:obj.title,
....
})
if (obj._parent)
foo(obj._parent)
}
foo(category)
You essentially want to get the list of ancestors.
const ancestors = []
var parent = category
while (parent) {
ancestors.push({
id: parent.id,
level: parent.level,
__parent: null
})
parent = parent.__parent
}
use recursion to extract objects:
const category = {
id: 1,
title: "a",
level: 2,
__parent: {
id: 2,
title: "b",
level: 1,
__parent: {
id: 3,
title: "c",
level: 0,
}
}
};
function extract(obj,arr=[]){
arr.push({...obj,__parent:null})
if(!obj.__parent){
return arr
}
return extract(obj.__parent,arr)
}
let result = extract(category)
console.log(result)
Using Spread/Rest Operator
const category = {
id: 1,
title: "a",
level: 2,
__parent: {
id: 2,
title: "b",
level: 1,
__parent: {
id: 3,
title: "c",
level: 0,
}
}
};
const {__parent, ...firstObject} = category;
result = [
firstObject,
{...category['__parent'], '__parent': null },
{...category['__parent']['__parent'], '__parent': null},
];
console.log(result);
Related
I have a json array like this:
(3) [{…}, {…}, {…}]
0: {Id: 1, Name: "bask"}
1: {Id: 2, Name: "voll"}
2: {Id: 3, Name: "badminton"}
I want to turn it into something like this:
{1:"bask",2:"voll",3:"badminton"}
You can use reduce to loop through array and build a object of desired key/value pair
let data = [{Id: 1, Name: "bask"},{Id: 2, Name: "voll"},{Id: 3, Name: "badminton"}]
let output = data.reduce((op, {Id, Name}) => {
op[Id] = Name
return op
},{})
console.log(output)
You could take Object.fromEntries with the maped key/value pairs.
var array = [{ Id: 1, Name: "bask" }, { Id: 2, Name: "voll" }, { Id: 3, Name: "badminton" }],
object = Object.fromEntries(array.map(({ Id, Name }) => [Id, Name]));
console.log(object);
You can check out the reduce() function!
let array = [
{Id: 1, Name: "bask"},
{Id: 2, Name: "voll"},
{Id: 3, Name: "badminton"}
];
console.log(_.reduce(array, function(result, obj){
result[obj.Id] = obj.Name;
return result;
}, {}));
You can checkout lodash an awesome library with many other such utilities!
You can do this with reduce():
var a = [
{Id: 1, Name: "bask"},
{Id: 2, Name: "voll"},
{Id: 3, Name: "badminton"}
]
b = a.reduce((acc, item) => {
acc[item.Id] = item.Name;
return acc;
}
console.log(b);
You can do it in different ways, here one of them.
let dataArray = [
{id: 1, name: 'bask'},
{id: 2, name: 'voll'},
{id: 3, name: 'badminton'}
]
let ouputObject = {}
dataArray.map(data => {
ouputObject[`${data.id}`] = data.name
})
console.log(ouputObject)
outputObject will be
Object {
1: "bask",
2: "voll",
3: "badminton"
}
Using Array.reduce() :
var arr = [{
Id: 1,
Name: "bask"
}, {
Id: 2,
Name: "voll"
}, {
Id: 3,
Name: "badminton"
}];
var reduceObj = arr.reduce(function(result, currentElement) {
result[currentElement.Id] = currentElement.Name;
return result;
}, {});
console.log(reduceObj);
Using Array.map() :
var arr = [{
Id: 1,
Name: "bask"
}, {
Id: 2,
Name: "voll"
}, {
Id: 3,
Name: "badminton"
}];
var mapObject = {}
arr.map(obj => {
mapObject[obj.Id] = obj.Name
})
console.log(mapObject);
I need to recursively get all children from a nested object.
I already wrote a function that does it (kinda) but I think it can be improved.
How can I make it shorter and cleaner?
I have included the data I'm using for testing as well as the function I wrote that needs improvement.
let data = [{
id: 1,
child: {
id: 2,
child: {
id: 3,
child: {
id: 4,
child: null
}
}
}
},
{
id: 5,
child: {
id: 6,
child: null
}
}
];
// function
for (let cat of data) {
cat.children = getCategoryChild(cat);
console.log(cat.children)
}
function getCategoryChild(cat) {
let t = [];
if (cat.child != null) {
t.push(cat.child);
let y = getCategoryChild(cat.child);
if (y.length > 0) {
for (let i of y) {
t.push(i)
}
}
}
return t;
}
Expected output:
[{id: 1, children: [{id: 2}, {id: 3}, {id: 4}]}, {id: 5, children: [{id: 6}]}]
You could take a recursive approach by checking the actual child property
function convert(array) {
const iter = o => o ? [{ id: o.id }, ...iter(o.child)] : [];
return array.map(({ id, child }) => ({ id, children: iter(child) }));
}
var data = [{ id: 1, child: { id: 2, child: { id: 3, child: { id: 4, child: null } } } }, { id: 5, child: { id: 6, child: null } }];
console.log(convert(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
assuming that each category only ever has one child
edited to adhere to the expected result...
function iterChildren(cat) {
let c = cat, children = [];
while (c.child) {
children.push({id: c.child.id});
c = c.child;
}
return {id: cat.id, children: children};
}
let newData = data.map(iterChildren);
I re-wrote the function.
It filters cats, and only returns an object with id and child_id of each.
let output = [],
data = [{
id: 1,
child: {
id: 2,
child: {
id: 3,
child: {
id: 4,
child: null
}
}
}
},
{
id: 5,
child: {
id: 6,
child: null
}
}
];
function getCategoryChild(cat) {
var t = [{
id: cat.id,
child_id: null
/* HERE you can set, what kind of data should be included to output */
}]
if (cat.child) {
t[0].child_id = cat.child.id
t = t.concat(getCategoryChild(cat.child))
}
return t
}
for (x of data) {
output=output.concat(getCategoryChild(x))
}
console.log(output)
EDIT: I edited my code assuming that one cat can have more children:
let output = [],
data = [{
id: 1,
child: {
id: 2,
child: {
id: 3,
child: {
id: 4,
child: null
}
}
}
},
{
id: 5,
child: {
id: 6,
child: null
}
},
{
id: 7,
child: [
{
id: 8,
child: {
id: 9,
child: null
}
},
{
id: 10,
child: null
},
{
id: 11,
child: null
}
]
},
];
function getCategoryChild(cat) {
var t = [{
id: cat.id,
child_id: []
/* HERE you can set, what kind of data should be included to output */
}]
if (cat.child) {
if (!(cat.child instanceof Array)) {
cat.child = [cat.child]
}
for (var x of cat.child) {
t[0].child_id.push(x.id)
t = t.concat(getCategoryChild(x))
}
}
return t
}
for (x of data) {
output = output.concat(getCategoryChild(x))
}
console.log(output)
data.map(({id,child:c})=>({id,children:[...{*0(){for(;c&&({id}=c);c=c.child)yield{id}}}[0]()]}))
This question already has answers here:
How to get the difference between two arrays of objects in JavaScript
(22 answers)
Closed 1 year ago.
I need some help. How can I get the array of the difference on this scenario:
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
I want the array of difference:
// [{ id: 2, name: 'pablo' }, { id: 3, name: 'escobar' }]
How is the most optimized approach?
I´m trying to filter a reduced array.. something on this line:
var Bfiltered = b1.filter(function (x) {
return x.name !== b2.reduce(function (acc, document, index) {
return (document.name === x.name) ? document.name : false
},0)
});
console.log("Bfiltered", Bfiltered);
// returns { id: 0, name: 'john' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ]
Thanks,
Robot
.Filter() and .some() functions will do the trick
var b1 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' },
{ id: 2, name: 'pablo' },
{ id: 3, name: 'escobar' }
];
var b2 = [
{ id: 0, name: 'john' },
{ id: 1, name: 'mary' }
];
var res = b1.filter(item1 =>
!b2.some(item2 => (item2.id === item1.id && item2.name === item1.name)))
console.log(res);
You can use filter to filter/loop thru the array and some to check if id exist on array 2
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = b1.filter(o => !b2.some(v => v.id === o.id));
console.log(result);
Above example will work if array 1 is longer. If you dont know which one is longer you can use sort to arrange the array and use reduce and filter.
var b1 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }, { id: 2, name: 'pablo' }, { id: 3, name: 'escobar' } ];
var b2 = [{ id: 0, name: 'john' }, { id: 1, name: 'mary' }];
var result = [b1, b2].sort((a,b)=> b.length - a.length)
.reduce((a,b)=>a.filter(o => !b.some(v => v.id === o.id)));
console.log(result);
Another possibility is to use a Map, allowing you to bring down the time complexity to O(max(n,m)) if dealing with a Map-result is fine for you:
function findArrayDifferences(arr1, arr2) {
const map = new Map();
const maxLength = Math.max(arr1.length, arr2.length);
for (let i = 0; i < maxLength; i++) {
if (i < arr1.length) {
const entry = arr1[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
if (i < arr2.length) {
const entry = arr2[i];
if (map.has(entry.id)) {
map.delete(entry.id);
} else {
map.set(entry.id, entry);
}
}
}
return map;
}
const arr1 = [{id:0,name:'john'},{id:1,name:'mary'},{id:2,name:'pablo'},{id:3,name:'escobar'}];
const arr2 = [{id:0,name:'john'},{id:1,name:'mary'},{id:99,name:'someone else'}];
const resultAsArray = [...findArrayDifferences(arr1,arr2).values()];
console.log(resultAsArray);
How to flatten this array :
[
{ID: 0 , TITLE: 'A', children: [{ID: 1, TITLE: 'AA'}]},
{ID: 2 , TITLE: 'B', children: []},
{ID: 3 , TITLE: 'C', children: [{ID: 4, TITLE: 'CC', children:[{ID: 5, TITLE: 'CCC'}]}]}
]
To get something like this :
A
A / AA
B
C / CC / CCC
You could use store the nested item of the actual object and take an iterative and recursive approach with a closure over the path.
For an incrementing ID, you could use either an additional variable for incrementing if a new row is found or iterate at the end the given array and add the index as id.
This proposal uses an additional id variable, because it requires no extra loop.
var array = [{ ID: 0, TITLE: 'A', children: [{ ID: 1, TITLE: 'AA' }] }, { ID: 2, TITLE: 'B', children: [] }, { ID: 3, TITLE: 'C', children: [{ ID: 4, TITLE: 'CC', children: [{ ID: 5, TITLE: 'CCC' }] }] }],
id = 0,
result = array.reduce(function f(p) {
return function (r, o) {
var temp = p.concat(o.TITLE);
r.push({ ID: id++, TITLE: temp.join('/') });
if (o.children) {
o.children.reduce(f(temp), r);
}
return r;
};
}([]), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
There's no need to complicate things here, you just need a function that loop over the array items, get their TITLE and if the item has children, we call the function recursively:
function getLevels(array, parent) {
var results = [];
array.forEach(function(el) {
results.push(!parent ? el["TITLE"] : parent + "/" + el["TITLE"]);
let prefix = parent ? parent + "/" + el["TITLE"] : el["TITLE"];
if (el.children && el.children.length > 0) {
getLevels(el.children, prefix).forEach(function(child) {
results.push(child);
});
}
});
return results;
}
Demo:
var arr = [{
ID: 0,
TITLE: 'A',
children: [{
ID: 1,
TITLE: 'AA'
}]
},
{
ID: 2,
TITLE: 'B',
children: []
},
{
ID: 3,
TITLE: 'C',
children: [{
ID: 4,
TITLE: 'CC',
children: [{
ID: 5,
TITLE: 'CCC'
}]
}]
}
];
function getLevels(array, parent) {
var results = [];
array.forEach(function(el) {
results.push(!parent ? el["TITLE"] : parent + "/" + el["TITLE"]);
let prefix = parent ? parent + "/" + el["TITLE"] : el["TITLE"];
if (el.children && el.children.length > 0) {
getLevels(el.children, prefix).forEach(function(child) {
results.push(child);
});
}
});
return results;
}
console.log(getLevels(arr));
Edit:
This is how to proceed to get the id in the array:
results.push({
"ID": el["ID"],
"TITLE": (!parent ? el["TITLE"] : parent + "/" + el["TITLE"])
});
Demo:
var arr = [{
ID: 0,
TITLE: 'A',
children: [{
ID: 1,
TITLE: 'AA'
}]
},
{
ID: 2,
TITLE: 'B',
children: []
},
{
ID: 3,
TITLE: 'C',
children: [{
ID: 4,
TITLE: 'CC',
children: [{
ID: 5,
TITLE: 'CCC'
}]
}]
}
];
function getLevels(array, parent) {
var results = [];
array.forEach(function(el) {
results.push({
"ID": el["ID"],
"TITLE": (!parent ? el["TITLE"] : parent + "/" + el["TITLE"])
});
let prefix = parent ? parent + "/" + el["TITLE"] : el["TITLE"];
if (el.children && el.children.length > 0) {
getLevels(el.children, prefix).forEach(function(child) {
results.push(child);
});
}
});
return results;
}
console.log(getLevels(arr));
Did you want something like this?
function merge(input, flat_array) {
if (!flat_array) {
// this is the initial recursive call, make the input
// (an array) have the same { child:[] } structure
// as children calls will end up having
flat_array = [];
input = { children: input };
} else {
// since the parent call is just a plain array it doesnt
// have a title so dont bother inserting anything
flat_array.push(input.TITLE);
}
for (let i in input.children) {
// recursively merge the children in into the flat array
// too
merge(input.children[i], flat_array);
}
return flat_array;
}
merge(x);
produces:
["A", "AA", "B", "C", "CC", "CCC"]
I have an array of objects, each with an 'id' and a 'name'. I'm retrieving an 'id' from the server and need to reorder the array starting from this id.
Example code:
var myList = [
{
id: 0,
name: 'Joe'
},
{
id: 1,
name: 'Sally'
},
{
id: 2,
name: 'Chris'
},
{
id: 3,
name: 'Tiffany'
},
{
id: 4,
name: 'Kerry'
}
];
Given an 'id' of 2, how can I reorder the array so my output is as follows:
var newList = [
{
id: 2,
name: 'Chris'
},
{
id: 3,
name: 'Tiffany'
},
{
id: 4,
name: 'Kerry'
},
{
id: 0,
name: 'Joe'
},
{
id: 1,
name: 'Sally'
}
];
Try this:
function orderList(list, id){
return list.slice(id).concat(list.slice(0,id));
}
Link to demo
You could slice the array at given index and return a new array using spread syntax.
const myList = [{id:0,name:'Joe'},{id:1,name:'Sally'},{id:2,name:'Chris'},{id:3,name:'Tiffany'},{id:4,name:'Kerry'}];
const slice = (arr, num) => [...arr.slice(num), ...arr.slice(0, num)];
console.log(slice(myList, 2));
myList.sort(function(a,b){
return a.id>2===b.id>2?a.id-b.id:b.id-a.id;
});
newList=myList;
http://jsbin.com/kenobunali/edit?console
You could splice the wanted part and use splice to insert it at the end of the array.
var myList = [{ id: 0, name: 'Joe' }, { id: 1, name: 'Sally' }, { id: 2, name: 'Chris' }, { id: 3, name: 'Tiffany' }, { id: 4, name: 'Kerry' }],
id = 2;
myList.splice(myList.length, 0, myList.splice(0, myList.findIndex(o => o.id === id)));
console.log(myList);
using es6 spread syntax
var myList = [{ id: 0, name: 'Joe' }, { id: 1, name: 'Sally' }, { id: 2, name: 'Chris' }, { id: 3, name: 'Tiffany' }, { id: 4, name: 'Kerry' }],
id = 2;
var index = myList.findIndex(o => o.id == id);
var arr = myList.splice(0, index);
var result = [...myList, ...arr];
console.log(result);