trim JS object to remove extra params with curly braces - javascript

I have an object response here
result.joblist = {
"collection_job_status_list": [
{
"application_context": {
"application_id": "a4",
"context_id": "c4"
},
"creation_time": "15699018476102",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
},
{
"application_context": {
"application_id": "a6",
"context_id": "c6"
},
"creation_time": "15698648632523",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
}
],
"result": {
"request_result": "ACCEPTED",
"error": {}
}
}
Need to get rid of {"application_context": & ending } here, just need application_id":"a4","context_id":"c4" at the same level.
I have tried something like this, but not able to move ahead.
var newObj: any = {};
if (allJobs && allJobs.length > 0) {
// this.rowData = this.allJobs;
// this.allJobs = this.allJobs['application_id'];
//let ele:object = allJobs.application_context;
allJobs.forEach(ele => {
newObj = {
application_id: ele.application_context.application_id,
context_id: ele.application_context.application_context
};
return newObj;
});
}

You can use map and destructuring
Get the collection_job_status_list from result
Loop over the values take out the required values from application_context key and merge with remaining values
Build the same structure as original result
let result = {"collection_job_status_list": [{"application_context": {"application_id": "a4","context_id": "c4"},"creation_time": "15699018476102","progress": 100,"status": "READY","phase": "ACTIVE","job_error": {}},{"application_context": {"application_id": "a6","context_id": "c6"},"creation_time": "15698648632523","progress": 100,"status": "READY","phase": "ACTIVE","job_error": {}}],"result": {"request_result": "ACCEPTED","error": {}}}
let { collection_job_status_list, ...rest } = result
let modified = collection_job_status_list.map(({
application_context: {
application_id,
context_id
},
...rest
}) => ({ ...rest, context_id, application_id}))
let final = {
collection_job_status_list: modified,
...rest
}
console.log(final)

What you need here is a map. Reference: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Try modifying the code as below and you should have your expected output.
var newObj: any = {};
var newArray;
if (allJobs && allJobs.length > 0) {
newArray = allJobs.map(ele => {
newObj = {
application_id: ele.application_context.application_id,
context_id: ele.application_context.application_context
};
return newObj;
});
}
Hope this helps :)

You need to use the map function
const result = {};
result.joblist = {
"collection_job_status_list": [
{
"application_context": {
"application_id": "a4",
"context_id": "c4"
},
"creation_time": "15699018476102",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
},
{
"application_context": {
"application_id": "a6",
"context_id": "c6"
},
"creation_time": "15698648632523",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
}
],
"result": {
"request_result": "ACCEPTED",
"error": {}
}
}
result.joblist.collection_job_status_list = result.joblist.collection_job_status_list.map(item => {
return {
"application_id": item.application_context.application_id,
"context_id": item.application_context.context_id
}
})
console.log(result)
Or you can use map function along with shorthand es6 syntaxes
const result = {};
result.joblist = {
"collection_job_status_list": [
{
"application_context": {
"application_id": "a4",
"context_id": "c4"
},
"creation_time": "15699018476102",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
},
{
"application_context": {
"application_id": "a6",
"context_id": "c6"
},
"creation_time": "15698648632523",
"progress": 100,
"status": "READY",
"phase": "ACTIVE",
"job_error": {}
}
],
"result": {
"request_result": "ACCEPTED",
"error": {}
}
}
result.joblist.collection_job_status_list = result.joblist.collection_job_status_list.map(({application_context}) => {
return {
...application_context
}
})
console.log(result)
EDIT:
The things you want to keep in your array depends on what you are returning from the map. You return the keys you want to keep. So if you want other items.
If you have an array A
A = [
{
nest: {
x: 1,
y: 1,
},
key1: 5,
key2: 7,
},
{
nest: {
x: 1,
y: 1,
},
key1: 5,
key2: 7,
},
{
nest: {
x: 1,
y: 1,
},
key1: 5,
key2: 7,
}
]
Let us assume you want x from nest, key1 and key2 in your final output. You will then do
const finalOutput = A.map(item => {
return {
x: item.nest.x, // x from nest
key1: item.key1, // key1
key2: item.key2, // key2
}
})
But there are shorthand forms for doing this. Let's assume that the item we get in our map function is already divided into a nest and a rest variable. The nest contains item.nest and the rest is {key1: 5,key2:7}, then you can simply return x from nest and everything else from rest
const finalOutput = A.map(({nest, ...rest}) => {
return {
x: nest.x, // x from nest
...rest, // everything else
}
})

Related

Remove a sub level of an array

I get a list of items with add-ons from the server, but when I try to delete an add-on from this list I can't. I noticed that when I try to access the property grupoAdicionais.produto.codigo, it does not exist because it has a sublevel coming from the API, how do I remove this to have access to my product.codigo?
Array received from API:
"grupoAdicionais":[
{"produto": {"codigo":21, "descricao":"Bacon"}, "item":148657, "quantidade":1, "total":5},
{"produto": {"codigo":13193, "descricao":"Queijo"}, "item":148657, "quantidade":1, "total":1}
]
My code in the reducer to return the list without the extra:
REMOVER_ADICIONAL: (state, action) => {
let itemRemover = action.item;
let listaReducer = state.lstItensRestauranteQRcode;
const itemRemovido = listaReducer.filter((item) => {
return item.grupoAdicionais.produto.codigo != itemRemover.produto.codigo;
});
state.lstItensRestauranteQRcode = itemRemovido;
},
If all you want to do is get a list of the codes:
const response = {"grupoAdicionais": [{
"produto": {
"codigo": 21,
"descricao": "Bacon"
},
"item": 148657,
"quantidade": 1,
"total": 5
}, {
"produto": {
"codigo": 13193,
"descricao": "Queijo"
},
"item": 148657,
"quantidade": 1,
"total": 1
}]}
const codigos = response.grupoAdicionais.map(grupo => grupo.produto.codigo)
console.log(codigos)
// =>
[ 21, 13193 ]
I'm not totally sure, but it seems like maybe you want to remove a group by its code.
const removeByCode = (code) => response.grupoAdicionais.filter((group) => group.produto.codigo !== code)
const newGroups = removeByCode(21)
console.log(newGroups)
// =>
[
{
produto: { codigo: 13193, descricao: 'Queijo' },
item: 148657,
quantidade: 1,
total: 1
}
]
var response = {"grupoAdicionais": [{
"produto": {
"codigo": 21,
"descricao": "Bacon"
},
"item": 148657,
"quantidade": 1,
"total": 5
}, {
"produto": {
"codigo": 13193,
"descricao": "Queijo"
},
"item": 148657,
"quantidade": 1,
"total": 1
}]}
console.dir(response.grupoAdicionais[0].produto.codigo)
grupoAdicionais is an array here, you have to access it like this:
console.dir(response.grupoAdicionais[0].produto.codigo)

How in JS to merge in one object two json objects where the ID of on object correspond on the same ID of the second object

My question relates to the fact I'm querying 2 different objects from DB and the result is in JSON. I need to merge them into one.
The 2 objects have in common this two key/value IRBId = ... and id = ... and they look as an example
OBJ 1
{
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
OBJ 2
{
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
...
"IRBId":"9",
},
{
"id":"92",
...
"IRBId":"8",
},
{
"id":"91",
...
"IRBId":"8",
}
],
}
},
As you will see above OBJ 2 and OBJ 1 corresponding with the same at IRBid and id.
What I need is to merge the two OBJ where IRBId OBJ 2 === id OBJ 1
The result I would expect after the merge is
OBJ merged
{
[{
"id":"93",
...
"IRBId":"9",
"irb": {
"name":"Again ",
...
}
},
{
"id":"92",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
},
{
"id":"91",
...
"IRBId":"8",
"irb": {
"name":"Admin ",
...
}
],
},
I don't know how to make it looks like this.
Try using Array.reduce
Logic
Loop through second object data nodes
Find the matching nodes from object 1 data nodes.
Push to accumulator with required details. (I have added only the nodes that was mentioned in in Expected resut, you can add asmuch as you need.)
const obj1 = {
"data": {
"IRBs": {
"nodes": [
{
"id": "8",
"name": "Admin ",
},
{
"id": "9",
"name": "Again",
}
],
}
}
}
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [
{
"id": "93",
"IRBId": "9",
},
{
"id": "92",
"IRBId": "8",
},
{
"id": "91",
"IRBId": "8",
}
],
}
},
};
const obj1List = obj1.data.IRBs.nodes;
const output = obj2.data.informedConsentForms.nodes.reduce((acc, curr) => {
const matchingNode = obj1List.find((item) => item.id === curr.IRBId);
if (matchingNode) {
acc.push({
id: curr.id,
IRBId: curr.IRBId,
irb: {
name: matchingNode.name
}
})
}
return acc;
}, []);
console.log(output);
You need to use the map function on the nodes in the first object to construct a new object that contains the second and first object's attributes.
const obj1 = {
"data": {
"IRBs": {
"nodes": [{
"id": "8",
"obj1": "one",
"name": "Admin ",
},
{
"id": "9",
"obj1": "two",
"name": "Again",
}
]
}
}
};
const obj2 = {
"data": {
"informedConsentForms": {
"count": 3,
"nodes": [{
"id": "93",
"obj2": "1",
"IRBId": "9",
},
{
"id": "92",
"obj2": "2",
"IRBId": "8",
},
{
"id": "91",
"obj2": "3",
"IRBId": "8",
}
],
}
}
};
const obj1Data = obj1.data.IRBs.nodes;
const obj2Data = obj2.data.informedConsentForms.nodes;
const res = obj2Data.map(item => {
const obj1Item = obj1Data.find(obj1Item => item.IRBId === obj1Item.id);
return obj1Item ? { ...item, "irb": { ...obj1Item}} : { ...item};
});
console.log(res);
i am using nested loop, try this one
const obj2 = {
"data":{
"informedConsentForms":{
"count":3,
"nodes":[
{
"id":"93",
"IRBId":"9",
},
{
"id":"92",
"IRBId":"8",
},
{
"id":"91",
"IRBId":"8",
}
],
}
},
}
const obj1 = {
"data":{
"IRBs":{
"nodes":[
{
"id":"8",
"name":"Admin ",
},
{
"id":"9",
"name":"Again",
}
],
}
}
}
const result = [];
const obj2Nodes = obj2.data.informedConsentForms.nodes;
for(let i = 0; i < obj2Nodes.length; i++) {
const obj1Nodes = obj1.data.IRBs.nodes
for(let j = 0; j < obj1Nodes.length; j++) {
if(obj2Nodes[i].IRBId === obj1Nodes[j].id) {
const {id, ...reObj1Nodes} = obj1Nodes[j];
result.push({
...obj2Nodes[i],
'irb': {
...reObj1Nodes
}
})
}
}
}
console.log(result)

Javascript Object array get last array

I have a json object array I have two functions. One to get the last message and the other to get. I need to keep the outer format the same but only return the one message.
I am getting the Json from the Telegram api and I have a Node Express script to return the reformatted Json
Here is the full Json:
{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I have a function to store the object after an api call to Telegram:
storeUpdates(data){
this.messageData = data;
}
For the function to get the last message:
getlastMessage() {
return
}
I am trying to return the Json:
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
And for the function to get a specific update_id
getNextMessage(update_id) {
return
}
Again I am trying to get this format of a single message matching the passed in update_id
{
"ok": true,
"result": [
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}
I am a little confused with the layers of object and arrays mixed.
Does this work?
const messages = {
ok: true,
result: [{
update_id: 650787950,
channel_post: {
message_id: 258,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256395,
text: 'test messge',
},
},
{
update_id: 650787951,
channel_post: {
message_id: 259,
chat: {
id: -1001497153100,
title: 'TestBot',
type: 'channel',
},
date: 1592256604,
text: 'next',
},
},
],
};
const getLastMessage = (messages) => {
final = {
ok: true,
result: [],
};
final.result.push(messages.result[messages.result.length - 1]);
return final;
};
const getNextMessage = (update_id, messages) => {
final = {
ok: true
};
final.result = messages.result.filter((msg) => {
return msg.update_id === update_id;
});
return final;
};
console.log(getLastMessage(messages));
console.log(getNextMessage(650787950, messages));
You get the last message by returning the last element in the array, by getting the length of the array and -1
I used Array.prototype.filter() to find the correct object.
To get the last result you would need to go to results and return the last index:
function getlastMessage(resultObject) {
return {
ok: resultObject.ok
result: [resultObject.result[resultObject.result.length - 1]]
}
}
To get the message by update_id:
getNextMessage(update_id) {
return {
ok: resultObject.ok
result: [resultObject.result.find(message => message.update_id === update_id)]
}
}
Something along these lines
Using destructuring you can make your code a little bit more compact:
const someObject = JSON.parse(`{
"ok": true,
"result": [
{
"update_id": 650787950,
"channel_post": {
"message_id": 258,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256395,
"text": "test messge"
}
},
{
"update_id": 650787951,
"channel_post": {
"message_id": 259,
"chat": {
"id": -1001497153100,
"title": "TestBot",
"type": "channel"
},
"date": 1592256604,
"text": "next"
}
}
]
}`)
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.find(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: someObject.result[arrayLength - 1]
}
}
console.log(getNextMessage(650787950))
console.log(getLastMessage())
If you want to keep the result type as an array you can use filter instead of find and surround the last element of result array with square brackets, like this:
const getNextMessage = (update_id) => {
return {
...someObject,
result: someObject.result.filter(message => message.update_id === update_id)
}
}
const getLastMessage = () => {
const arrayLength = someObject.result.length;
return {
...someObject,
result: [someObject.result[arrayLength - 1]]
}
}

Modify javascript object to specific format

let data = {
"rec": [{
"id": "25837",
"contentId": "25838"
},
{
"id": "25839",
"contentId": "25838"
},
{
"id": "25838"
},
{
"id": "25636",
"contentId": "25837"
}, {
"id": "25640",
"contentId": "25839"
}
]
};
I have a javascript object which I have to manipulate to below format.
{
"childern": [{
"id": "25838",
"childern": [{
"id": "25837",
"contentId": "25838",
"childern": [{
"id": "25636",
"contentId": "25837"
}]
},
{
"id": "25839",
"contentId": "25838",
"childern": [{
"id": "25640",
"contentId": "25839"
}]
}
]
}]
}
If any object dont have contentId it should be at parent level. then all the objects having contentId same as parent id should be at its child level and so on.
I have created a fiddle here but logic is not completed. Any idea or reference to achieve this.
You could create recursive function with reduce method to get the desired result.
let data = {"rec":[{"id":"25837","contentId":"25838"},{"id":"25839","contentId":"25838"},{"id":"25838"},{"id":"25636","contentId":"25837"},{"id":"25640","contentId":"25839"}]}
function nest(data, pid) {
return data.reduce((r, e) => {
if (pid == e.contentId) {
const obj = { ...e }
const children = nest(data, e.id);
if (children.length) obj.children = children
r.push(obj)
}
return r;
}, [])
}
const result = nest(data.rec);
console.log(result[0])

How to merge objects with the same properties into an Array?

I would like to merge 2 objects with the same properties into an Array.
Take this for an example:
object1 = {"id":1,
"name":name1,
"children":[{"id":2,"name":name2}]
};
object2 = {"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
};
object3 = {"id":1,
"name":name1,
"children":[{"id":6,"name":name6}]
};
var result = Object.assign(result,object1,object2,object3);
Expected result:
JSON.stringify([result]) =[
{"id":1,
"name":name1,
"children":[{"id":2,"name":name2},
{"id":6,"name":name6}]
},
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
Actual result:
JSON.stringify([result]) = [
{"id":3,
"name":name3,
"children":[{"id":4,"name":name4}]
}
]
Seems like Object.assign() isn't the way to go... as it will overwrite, I do not want it to overwrite, I want them to merge instead. Is there a right way to do this?
As so often, Array.prototype.reduce provides a good base for an approach like e.g. this one ...
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6" }]
};
// Expected result: [{
// "id": 1,
// "name": name1,
// "children": [
// { "id": 2, "name": "name2" },
// { "id": 6, "name": "name6" }
// ]
// }, {
// "id": 3,
// "name": "name3",
// "children": [{"id": 4, "name": "name4" }]
// }]
function mergeEquallyLabeledTypes(collector, type) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
return collector;
}
var result = [obj1, obj2, obj3].reduce(mergeEquallyLabeledTypes, {
store: {},
list: []
}).list;
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
Edit Note
After having been informed about changed requirements, that need to deal with a nested pattern, I will change my first provided approach into a generic solution. It will be not that difficult since there is a generically repeated pattern within the data structure. Thus I just need to make the already existing reducer function self recursive. A recursion step will be triggered after having finished a complete reducing cycle on any provided list ...
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2", "children": [{ "id": 8, "name": "name8" }] }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", "children": [{ "id": 9, "name": "name9" }] }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6", "children": [{ "id": 10, "name": "name10" }] }]
};
var obj4 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", "children": [{ "id": 11, "name": "name11" }] }]
};
function mergeEquallyLabeledTypesRecursively(collector, type, idx, list) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
// take repetitive data patterns into account ...
if (idx >= (list.length - 1)) {
collector.list.forEach(function (type) {
// ... behave recursive, when appropriate.
if (type.children) {
type.children = type.children.reduce(mergeEquallyLabeledTypesRecursively, {
store: {},
list: []
}).list;
}
});
}
return collector;
}
var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypesRecursively, {
store: {},
list: []
}).list;
console.log('result : ', result);
.as-console-wrapper { max-height: 100%!important; top: 0; }
This might be what your after, please note it's not recursive now recursive. But your example data doesn't appear to be anyway.
const object1 = {"id":1,
"name":"name1",
"children":[{"id":2,"name":"name2"}]
};
const object2 = {"id":3,
"name":"name3",
"children":[{"id":4,"name":"name4"}]
};
const object3 = {"id":1,
"name":"name1",
"children":[
{"id":6,"name":"name6"},
{"id":7,"name":"name7"},
{"id":6,"name":"name6"}
]
};
function merge(arr) {
const idLinks = {};
const ret = [];
arr.forEach((r) => {
if (!idLinks[r.id]) idLinks[r.id] = [];
idLinks[r.id].push(r);
});
Object.keys(idLinks).forEach((k) => {
const nn = idLinks[k];
const n = nn[0];
for (let l = 1; l < nn.length; l ++) {
if (nn[l].children) {
if (!n.children) n.children = [];
n.children = n.children.concat(nn[l].children);
}
}
if (n.children && n.children.length) n.children = merge(n.children);
ret.push(n);
});
return ret;
}
var result = merge([object1,object2,object3]);
console.log(result);
/* There are two cases :
a) No duplicate children
b) Duplicate children either in (same object || different object|| both)
*/
/* =============== */
/* Case a) */
const util = require('util');
var object1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
var object2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
var object3 = {
"id": 1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var arr = [object1,object2,object3];
var uniqueIds = [];
var filteredArray = [];
var uniqueId='';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
});
console.log(util.inspect(filteredArray,false,null));
/* ============================================
Case b)
Dealing with the worst case of having duplicate children in both same
and different objects
*/
object1 = {"id":1,
"name":'name1',
"children":[{"id":2,"name":'name2'},
{"id":2,"name":'name2'}]
};
object2 = {"id":3,
"name":'name3',
"children":[{"id":4,"name":'name4'}]
};
object3 = {"id":1,
"name":'name1',
"children":[{"id":6,"name":'name6'},
{"id":7,"name":'name7'},
{"id":2,"name":'name2'}]
};
arr = [object1,object2,object3];
uniqueIds = [];
uniqueId = '';
arr.map((item,i,array)=>{
uniqueId =uniqueIds.indexOf(item.id);
uniqueId = uniqueId+1;
uniqueIds = [...uniqueIds,item.id];
if(!uniqueId){
filteredArray[i] = item;
}
if(uniqueId){
filteredArray[uniqueId-1]['children'] = [...(array[uniqueId-1].children),...(item.children)];
}
/*Removing duplicate children entries*/
filteredArray[uniqueIds.indexOf(item.id)]['children'] = filteredArray[uniqueIds.indexOf(item.id)]['children']
.filter((elem, index, self) => self.findIndex((t) => {return t.id === elem.id}) === index)
})
console.log(util.inspect(filteredArray,false,null));
In functional programming way with es6 standards. I am assuming children array also contains duplicates. I enclosed the code in closures.
See the following link why I used util to print all the object in node console.log()
How can I get the full object in Node.js's console.log(), rather than '[Object]'?
(function() {
'use strict';
const util = require('util');
/** string constants */
const ID = 'id';
const CHILDREN = 'children';
/* Objects to modify */
const object1 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 2, "name": "name2" },
{ "id": 5, "name": "name5" },
{ "id": 7, "name": "name7" }
]
};
const object2 = {
"id": 3,
"name": "name3",
"children": [
{ "id": 4, "name": "name4" }
]
};
const object3 = {
"id": 1,
"name": "name1",
"children": [
{ "id": 5, "name": "name5" },
{ "id": 6, "name": "name6" }
]
};
/**
* Concates the arrays
* #param { array } - a
* #param { array } - b
*/
const merge = (a, b) => {
return a.concat(b);
};
/**
* Removes Duplicates from the given array based on ID
* #param { array } - array to remove duplicates
* #return { array } - array without duplicates
*/
const removeDuplicates = (arr) => {
return arr.filter((obj, pos, arr) => {
return arr.map((m) => {
return m[ID];
}).indexOf(obj[ID]) === pos;
});
}
/**
* Groups items in array with particular key
* Currying technique
* #param { prop } - key to group
* #return { () => {} } - Method which in turn takes array as argument
*/
const groupBy = (prop) => (array) => {
return array.reduce((groups, item) => {
const val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
}
/**
* Object containing grouped-items by particuar key
*/
const grouped = groupBy(ID)([object1, object2, object3]);
/**
* Removing the duplicates of children
* Remember map also mutates the array of objects key's value
* but not data type
*/
Object.keys(grouped).map((key, position) => {
grouped[key].reduce((a, b) => {
a[CHILDREN] = removeDuplicates(a[CHILDREN].concat(b[CHILDREN]));
});
});
/**
* Desired final output
*/
const final = Object.keys(grouped)
.map((key) => removeDuplicates(grouped[key]))
.reduce(merge, []);
console.log(util.inspect(final, false, null))})();
const object1 = {
"id":1,
"name":"name1",
"children":[{"id":2,"name":"name2"}]
};
const object2 = {
"id":3,
"name":"name3",
"children":[{"id":4,"name":"name4"}]
};
const object3 = {
"id":1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
var array = [object1,object2,object3];
var array2 = [object1,object2,object3];
function uniquearray(obj){
var result =[];
for(var i=0;i<array.length;i++){
if(obj.id == array[i].id){
result.push(array[i])
array.splice(i,1)
}
}
return result;
}
var arrayofuniarrays = []
for(var i=0;i<array2.length;i++){
arrayofuniarrays.push(uniquearray(array2[i]))
}
for(var i=0;i<arrayofuniarrays.length;i++){
for(var j=1;j<arrayofuniarrays[i].length; j++){
arrayofuniarrays[i][0].children.push(arrayofuniarrays[i][j].children)
arrayofuniarrays[i].splice(j,1)
}
}
var resul = arrayofuniarrays.reduce(function(a, b){return a.concat(b)},[])
console.log(resul)
Here is a sketch example of how to do this. It leverages a mapped type using your id as a key to ensure each item only appears once. It adds all of the children to an array based on the id.
If you needed to enforce the same behaviour on the children, you could use the same technique.
I have split this into multiple iterations to show you the individual parts in play.
Usually, it is more efficient to avoid creating objects that need to be zipped back up if you can.
const object1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2" }]
};
const object2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4" }]
};
const object3 = {
"id": 1,
"name":"name1",
"children":[{"id":6,"name":"name6"}]
};
const all = [object1, object2, object3];
// Use a map like a dictionary to enforce unique keys
const mapped = {};
for (let obj of all) {
if (!mapped[obj.id]) {
mapped[obj.id] = obj;
continue;
}
mapped[obj.id].children.push(obj.children);
}
console.log('Mapped ==> '+JSON.stringify(mapped));
// If you want to convert the mapped type to an array
const result = [];
for (let key in mapped) {
result.push(mapped[key]);
}
console.log('Array ==> '+JSON.stringify(result));
Building on #Peter Seliger's answer here, I derived with the following method to merge arrays with deeply nested children.
Given the following objects:
var obj1 = {
"id": 1,
"name": "name1",
"children": [{ "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] }]
};
var obj2 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":9, "name": "name9" }] }]
};
var obj3 = {
"id": 1,
"name": "name1",
"children": [{ "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }]
};
var obj4 = {
"id": 3,
"name": "name3",
"children": [{ "id": 4, "name": "name4", children:[{ "id":11, "name": "name11" }] }]
};
First we merge the parents
function mergeEquallyLabeledTypes(collector, type) {
var key = (type.name + '#' + type.id); // identity key.
var store = collector.store;
var storedType = store[key];
if (storedType) { // merge `children` of identically named types.
if(storedType.children)
storedType.children = storedType.children.concat(type.children);
} else {
store[key] = type;
collector.list.push(type);
}
return collector;
}
var result = [obj1, obj2, obj3, obj4].reduce(mergeEquallyLabeledTypes, {
store: {},
list: []
}).list;
Then we merge the children and subchildren if any.
for(let i=0; i<result.length; i++){
var children = result[i].children;
if(children){
var reducedChildren = children.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
for(let j=0; j<reducedChildren.length; j++){
var subchildren = reducedChildren[j].children;
if(subchildren){
var reducedSubchildren = subchildren.reduce(mergeEquallyLabeledTypes, {store: {}, list: []}).list;
reducedChildren[j].children = reducedSubchildren;
}
}
result[i].children = reducedChildren;
}
}
Finally the result will be what I'll parse into my website.
console.log('result : ', result);
I am able to get the expected result.
// result: [{
// "id": 1,
// "name": name1,
// "children": [
// { "id": 2, "name": "name2", children:[{ "id":8, "name": "name8" }] },
// { "id": 6, "name": "name6", children:[{ "id":10, "name": "name10" }] }
// ]
// }, {
// "id": 3,
// "name": "name3",
// "children": [{"id": 4, "name": "name4", children:[
// { "id":9, "name": "name9" },
// { "id":11, "name": "name11" }
// ]
// }
// ]
// }]
However, this might not be too efficient as I'll need to keep adding on to the merging of children/subchildren method if my tree get nested with more levels. (e.g. subsubchildren, subsubsubchildren and so on...)
Is there any more efficient way to do this?
const object1 = {
id:1,
name:'a',
}
const object2 = {
id:3,
name:'b',
}
const object3 = {
id:1,
name:'c',
}
const originArr = [object1, object2, object3]
const idArr = [object1.id, object2.id, object3.id]
const newIdArr = []
for (let id of idArr) {
if (newIdArr.indexOf(id)) newIdArr.push(id)
}
const result = newIdArr.map(id => {
let names = []
for (obj of originArr) {
if (id === obj.id) names.push(obj.name)
}
return { id, names }
})
console.log(result)

Categories

Resources