Combine two different sized array of objects in javascript [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have two different sized arrays like this
[{ id: 1, name: 'One', contacts: [] },
{ id: 2, name: 'Two', contacts: [] },
{ id: 3, name: 'Three', contacts: [] },
{ id: 4, name: 'Four', contacts: [] }]
[{ id: 1, name: 'One', contacts: [{ id: 100, name: "C1" }, { id: 101, name: "C2" }] },
{ id: 3, name: 'Three', contacts: [{ id: 120, name: "C1" }, { id: 121, name: "C2" }] },
{ id: 5, name: 'Five', contacts: [{ id: 420, name: "F1" }, { id: 421, name: "F2" }] }];
I tried with below code in javascript
const mergeArray = (source, merge, by) => source.map(item => ({
...item,
...(merge.find(i => i[by] === item[by]) || {}),
}));
output = mergeArray(this.oldArray1,this.oldArray2,'id');
It gives output as
[{ id: 1, name: 'One', contacts: [{ id: 100, name: "C1" }, { id: 101, name: "C2" }] },
{ id: 2, name: 'Two', contacts: [] }
{ id: 3, name: 'Three', contacts: [{ id: 120, name: "C1" }, { id: 121, name: "C2" }] }]
But desired output like this
[{ id: 1, name: 'One', contacts: [{ id: 100, name: "C1" }, { id: 101, name: "C2" }] },
{ id: 2, name: 'Two', contacts: [] }
{ id: 3, name: 'Three', contacts: [{ id: 120, name: "C1" }, { id: 121, name: "C2" }] },
{ id: 4, name: 'Four', contacts: [] }
{ id: 5, name: 'Five', contacts: [{ id: 420, name: "F1" }, { id: 421, name: "F2" }] }]

you could collect the arrays in an array, or simply concat the arrays and then reduce this array by checkin if the id is in the result array. If not add the object to the result array or if exist, then extend contacts with the acutal data.
var array1 = [{ id: 1, name: 'One', contacts: [] }, { id: 2, name: 'Two', contacts: [] }, { id: 3, name: 'Three', contacts: [] }, { id: 4, name: 'Four', contacts: [] }],
array2 = [{ id: 1, name: 'One', contacts: [{ id: 100, name: "C1" }, { id: 101, name: "C2" }] }, { id: 3, name: 'Three', contacts: [{ id: 120, name: "C1" }, { id: 121, name: "C2" }] }, { id: 5, name: 'Five', contacts: [{ id: 420, name: "F1" }, { id: 421, name: "F2" }] }],
merged = [array1, array2].reduce((r, a) => {
a.forEach(o => {
var object = r.find(({ id }) => id === o.id);
if (!object) {
return r.push(o);
}
object.contacts.push(...o.contacts);
});
return r;
}, []);
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

Creating an array by nested map with filtering

const market = [
{
id: 0,
properties: [{ name: 'salad', price: 99, isMain: true }],
value: "1"
},
{
id: 1,
properties: [{ name: 'patato', price: 100, isMain: false }],
value: "2"
},
{
id: 2,
properties: [{ name: 'strawberry', price: 101, isMain: true }],
value: "3"
},
];
I have data like above, I want to make list of properties which has isMain property is true like the example below. How can I best do this with ES6?
expectation ==>
[
{
name: 'salad',
price: 99,
isMain: true,
},
{
name: 'strawberry',
price: 101,
isMain: true,
},
];
You need to flat the array and then use the filter method to get your desired items from nested array, this will work even if you have multiple items in properties array.
var filtredItems = [];
const market = [
{
id: 0,
properties: [{ name: 'salad', price: 99, isMain: true }],
value: "1"
},
{
id: 1,
properties: [{ name: 'patato', price: 100, isMain: false }, { name: 'second', price: 100, isMain: true }],
value: "2"
},
{
id: 2,
properties: [{ name: 'strawberry', price: 101, isMain: true }],
value: "3"
},
];
filtredItems = market.flatMap(x => x.properties).filter(prop=> prop.isMain);
console.log('filtredItems', filtredItems)
Use ES6 map then filter
const market = [
{
id: 0,
properties: [{ name: 'salad', price: 99, isMain: true }],
value: "1"
},
{
id: 1,
properties: [{ name: 'patato', price: 100, isMain: false }],
value: "2"
},
{
id: 2,
properties: [{ name: 'strawberry', price: 101, isMain: true }],
value: "3"
},
];
const results = market.map(product => product.properties[0]).filter(p => !!p.isMain);
console.log(results);
NB: it is quite weird to have a single hash in an array.
you can bind filter with map to get somthing like this
i don't know if you have multiple values in properties field:
market.filter(m => m.properties?.[0].isMain)
.map( m => ({ name: m.name, price: m.properties?.[0].isMain, isMain: m.properties?.[0].isMain }))

How to get list of parents id in json object

My nested json array looks like:
[
{
id: 1,
name: "Mike",
children: [
{ id: 2, name: "MikeC1" },
{ id: 3, name: "MikeC2" },
{
id: 4, name: "MikeC3",
children: [{ id: 5, name: "MikeCC1" }]
},
]
},
{
id: 6,
name: "Json",
children: [
{ id: 7, name: "JsonC1" },
{ id: 8, name: "JsonC2" },
{
id: 9, name: "JsonC3",
children: [{ id: 10, name: "JsonCC1" },{ id: 11, name: "JsonCC2" }]
},
]
}
]
Now I get a id like "11"
then get the parent ids array in json like [6,9,11]
How to do?
var id = 11
console.log(findParent(id))
//result is [6,9,11]
You need to do recursive search
const persons = [
{
id: 1,
name: "Mike",
children: [
{ id: 2, name: "MikeC1" },
{ id: 3, name: "MikeC2" },
{
id: 4, name: "MikeC3",
children: [{ id: 5, name: "MikeCC1" }]
},
]
},
{
id: 6,
name: "Json",
children: [
{ id: 7, name: "JsonC1" },
{ id: 8, name: "JsonC2" },
{
id: 9, name: "JsonC3",
children: [{ id: 10, name: "JsonCC1" },{ id: 11, name: "JsonCC2" }]
},
]
}
];
function searchRecursive(items, id) {
const allIds = [];
items.forEach(item => {
if(item.id === id) {
allIds.push(item.id);
}
else if(item.children) {
const ids = searchRecursive(item.children, id);
if(ids.length) allIds.push(item.id);
ids.forEach(id => allIds.push(id));
}
});
return allIds;
}
console.log(searchRecursive(persons, 11));

How to flatten the nested Array?

How do I flatten the nested Array in the Array?
Here is the example input Array,
const input = [
{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}, {
id: 4,
name: 'Charles',
otherFields: [{
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
}
]
Output Array I want to get.
[{
id: 1,
name: 'Charles'
}, {
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}, {
id: 4,
name: 'Charles'
}, {
id: 5,
name: 'Pung',
}, {
id: 6,
name: 'James',
}]
I want to somehow get the output in one statement like
input.map((sth) => ({...sth??, sth.field...})); // I'm not sure :(
With flatMap you can take out the otherFields property, and returning an array containing the parent item and the other array:
const input = [{
id: 1,
name: 'Charles',
otherFields: [{
id: 2,
name: 'Pung',
}, {
id: 3,
name: 'James',
}]
}];
console.log(
input.flatMap(({ otherFields, ...item }) => [item, ...otherFields])
);
For more than one level, you could take a recursive approach of flattening.
const
flat = ({ otherFields = [], ...o }) => [o, ...otherFields.flatMap(flat)],
input = [{ id: 1, name: 'Charles', otherFields: [{ id: 2, name: 'Pung' }, { id: 3, name: 'James', otherFields: [{ id: 4, name: 'Jane' }] }] }],
result = input.flatMap(flat);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sort array of nested objects into separate array of arrays

I have an array:
[
{ id: 1,
name: "parent1",
children: [
{ id: 10,
name: "first_child_of_id_1",
children: [
{ id: 100, name: "child_of_id_10", children: []},
{ id: 141, name: "child_of_id_10", children: []},
{ id: 155, name: "child_of_id_10", children: []}
]
},
{ id: 42,
name: "second_child_of_id_1",
children: [
{ id: 122, name: "child_of_id_42", children: []},
{ id: 133, name: "child_of_id_42", children: []},
{ id: 177, name: "child_of_id_42", children: []}
]
}
]
},
{ id: 7,
name: "parent7",
children: [
{ id: 74,
name: "first_child_of_id_7",
children: [
{ id: 700, name: "child_of_id_74", children: []},
{ id: 732, name: "child_of_id_74", children: []},
{ id: 755, name: "child_of_id_74", children: []}
]
},
{ id: 80,
name: "second_child_of_id_7",
children: [
{ id: 22, name: "child_of_id_80", children: []},
{ id: 33, name: "child_of_id_80", children: []},
{ id: 77, name: "child_of_id_80", children: []}
]
}
]
}
]
What I need is an array of arrays like this:
[
[ "id", "name", "parent_id", "parent_name" ],
[ 1, "parent1", null, "" ],
[ 10, "first_child_of_id_1", 1, "parent1"],
[ 42, "second_child_of_id_1", 1, "parent1"],
[100, "child_of_id_10", 10, "first_child_of_id_1"]
]
and so on for all nested objects for me to convert them into CSV rows. I've checked many answers and found a similar problem here: How to convert array of nested objects to CSV?
But it produces too long rows for many nested objects and I am not experienced enough with JavaScript to modify map function.
const categories = [
{ id: 1,
name: "parent1",
children: [
{ id: 10,
name: "first_child_of_id_1",
children: [
{ id: 100, name: "child_of_id_10", children: []},
{ id: 141, name: "child_of_id_10", children: []},
{ id: 155, name: "child_of_id_10", children: []}
]
},
{ id: 42,
name: "second_child_of_id_1",
children: [
{ id: 122, name: "child_of_id_42", children: []},
{ id: 133, name: "child_of_id_42", children: []},
{ id: 177, name: "child_of_id_42", children: []}
]
}
]
},
{ id: 7,
name: "parent7",
children: [
{ id: 74,
name: "first_child_of_id_7",
children: [
{ id: 700, name: "child_of_id_74", children: []},
{ id: 732, name: "child_of_id_74", children: []},
{ id: 755, name: "child_of_id_74", children: []}
]
},
{ id: 80,
name: "second_child_of_id_7",
children: [
{ id: 22, name: "child_of_id_80", children: []},
{ id: 33, name: "child_of_id_80", children: []},
{ id: 77, name: "child_of_id_80", children: []}
]
}
]
}
]
function pivot(arr) {
var mp = new Map();
function setValue(a, path, val) {
if (Object(val) !== val) { // primitive value
var pathStr = path.join('.');
var i = (mp.has(pathStr) ? mp : mp.set(pathStr, mp.size)).get(pathStr);
a[i] = val;
} else {
for (var key in val) {
setValue(a, key == '0' ? path : path.concat(key), val[key]);
}
}
return a;
}
var result = arr.map(obj => setValue([], [], obj));
return [[...mp.keys()], ...result];
}
function toCsv(arr) {
return arr.map(row =>
row.map(val => isNaN(val) ? JSON.stringify(val) : +val).join(',')
).join('\n');
}
<button onclick="console.log(toCsv(pivot(categories)))">Output</button>
Simple DFS or BFS algorithm should do the job here.
The difference is the order of created "rows". If you want to have all children of given node listed immediately after their parent, then you need to use BFS.
Example with DFS and BFS:
const input = [{
id: 1,
name: "parent1",
children: [{
id: 10,
name: "first_child_of_id_1",
children: [{
id: 100,
name: "child_of_id_10",
children: []
},
{
id: 141,
name: "child_of_id_10",
children: []
},
{
id: 155,
name: "child_of_id_10",
children: []
}
]
},
{
id: 42,
name: "second_child_of_id_1",
children: [{
id: 122,
name: "child_of_id_42",
children: []
},
{
id: 133,
name: "child_of_id_42",
children: []
},
{
id: 177,
name: "child_of_id_42",
children: []
}
]
}
]
},
{
id: 7,
name: "parent7",
children: [{
id: 74,
name: "first_child_of_id_7",
children: [{
id: 700,
name: "child_of_id_74",
children: []
},
{
id: 732,
name: "child_of_id_74",
children: []
},
{
id: 755,
name: "child_of_id_74",
children: []
}
]
},
{
id: 80,
name: "second_child_of_id_1",
children: [{
id: 22,
name: "child_of_id_80",
children: []
},
{
id: 33,
name: "child_of_id_80",
children: []
},
{
id: 77,
name: "child_of_id_80",
children: []
}
]
}
]
}
]
//DFS
function deepWalk(node, parent, output = []) {
if (!node || typeof node !== 'object' || !node.id) return;
output.push([node.id, node.name, parent ? parent.id : null, parent ? parent.name : ""])
if (node.children) {
for (const child of node.children) {
deepWalk(child, node, output);
}
}
return output;
}
//BFS
function broadWalk(root) {
const output = []
const queue = [];
queue.push({
node: root,
parent: null
});
while (queue.length) {
const {
node,
parent
} = queue.shift();
output.push([node.id, node.name, parent ? parent.id : null, parent ? parent.name : ""])
if (node.children) {
for (const child of node.children) {
queue.push({
node: child,
parent: node
});
}
}
}
return output;
}
let rowsDfs = [
["id", "name", "parent_id", "parent_name"]
];
let rowsBfs = [
["id", "name", "parent_id", "parent_name"]
];
for (const node of input) {
rowsDfs = [...rowsDfs, ...deepWalk(node)];
rowsBfs = [...rowsBfs, ...broadWalk(node)];
}
console.log("rows DFS: ", rowsDfs)
console.log("rows BFS: ", rowsBfs)

How to unwind an Array of Objects in NodeJS?

I want to unwind an array of objects which have arrays of objects nested. The level of nesting is not defined and is not consistent throughout the array.
Here's my sample data
var data = [{
id: 1,
name: 'Harshal',
subjects: [{
id: 1,
name: 'English',
chapters: [{
id: 1,
name: 'Grammar'
}, {
id: 2,
name: 'Comprehension'
}]
}, {
id: 2,
name: 'Maths',
chapters: [{
id: 1,
name: 'Algebra'
}, {
id: 2,
name: 'Geometry'
}]
}]
}, {
id: 2,
name: 'Pankaj',
subjects: [{
id: 3,
name: 'Marathi',
chapters: [{
id: 1,
name: 'Kavita',
topics: [{
id: 1,
name: 'Topic 1'
}]
}]
}, {
id: 4,
name: 'Hindi',
chapters: [{
id: 1,
name: 'Katha',
topics: [{
id: 2,
name: 'Topic 2'
}, {
id: 3,
name: 'Topic 3'
}]
}]
}]
}];
I want to get an output like this:
var op = [{
id: 1,
name: 'Harshal',
subjects: {
id: 1,
name: 'English',
chapters: {
id: 1,
name: 'Grammar'
}
}
}, {
id: 1,
name: 'Harshal',
subjects: {
id: 1,
name: 'English',
chapters: {
id: 2,
name: 'Comprehension'
}
}
}, {
id: 1,
name: 'Harshal',
subjects: {
id: 2,
name: 'Maths',
chapters: {
id: 1,
name: 'Algebra'
}
}
}, {
id: 1,
name: 'Harshal',
subjects: {
id: 2,
name: 'Maths',
chapters: {
id: 2,
name: 'Geometry'
}
}
}, {
id: 2,
name: 'Pankaj',
subjects: {
id: 3,
name: 'Marathi',
chapters: {
id: 1,
name: 'Kavita',
topics: {
id: 1,
name: 'Topic 1'
}
}
}
}, {
id: 2,
name: 'Pankaj',
subjects: {
id: 4,
name: 'Hindi',
chapters: {
id: 1,
name: 'Katha',
topics: {
id: 2,
name: 'Topic 2'
}
}
}
}, {
id: 2,
name: 'Pankaj',
subjects: {
id: 4,
name: 'Hindi',
chapters: {
id: 1,
name: 'Katha',
topics: {
id: 3,
name: 'Topic 3'
}
}
}
}];
I have tried to work with pull-unwind but I guess there's some issues with it. If anyone has any other ideas, I'm open to implement those.
Have you tried recursion?
var data = [{
id: 1,
name: 'Harshal',
subjects: [{
id: 1,
name: 'English',
chapters: [{
id: 1,
name: 'Grammar'
}, {
id: 2,
name: 'Comprehension'
}]
}, {
id: 2,
name: 'Maths',
chapters: [{
id: 1,
name: 'Algebra'
}, {
id: 2,
name: 'Geometry'
}]
}]
}, {
id: 2,
name: 'Pankaj',
subjects: [{
id: 3,
name: 'Marathi',
chapters: [{
id: 1,
name: 'Kavita',
topics: [{
id: 1,
name: 'Topic 1'
}]
}]
}, {
id: 4,
name: 'Hindi',
chapters: [{
id: 1,
name: 'Katha',
topics: [{
id: 2,
name: 'Topic 2'
}, {
id: 3,
name: 'Topic 3'
}]
}]
}]
}];
function unravel(obj)
{
var out = [];
var added = false;
for(var i in obj) {
if(obj[i] instanceof Array) {
for(var j in obj[i]) {
var r = unravel(obj[i][j]);
for(var k in r) {
var a = {};
for(var key in obj) { // make copy of obj
a[key] = obj[key];
}
a[i] = r[k];
added = true;
out.push(a);
}
}
}
}
if(!added) {
out.push(obj);
}
return out;
}
var op = [];
for(var i in data)
op = op.concat(unravel(data[i]));
console.log(JSON.stringify(op, null, 4));

Categories

Resources