I have below json array I want to group by it based on sourceno and destno combine key.
Present Code:
let eddarr=[
{
"sourceno": "112",
"destno": "321",
"edno": "123",
"eppno": "322"
},
{
"sourceno": "112",
"destno": "321",
"edno": "123",
"eppno": "324"
},
{
"sourceno": "114",
"destno": "335",
"edno": "100",
"eppno": "355"
},
{
"sourceno": "114",
"destno": "335",
"edno": "222",
"eppno": "999"
}
]
let pobj={}
let p_data=[]
let count=0;
for(key in eddarr)
{
let resultarr=eddarr[key]
let pkey = eddarr[key].sourceno+'-'+eddarr[key].destno;
let obj = {};
let isNew = true;
if(pdata.length > 0){
for(let j=0;j<pdata.length;j++){
if(pdata[j].hasOwnProperty(pkey)){
pdata[j][pkey][pdata[j][pkey].length] = resultarr;
isNew = false;
break;
}
}
}
if(isNew){
obj[pkey] = new Array();
obj[pkey][0] = resultarr;
pdata.push(obj);
}
console.log(pdata)
Above code is working fine and i am getting below result but its running very slow its creating below result for 37K records after 15 min. How can i optimise this code or any other logic need to build. I want to process 1.5 million records but loop is taking too much time.
Final result after processing should be like this:
[
{
"112-321": [
{
"edno": "123",
"eppno": "322"
},
{
"edno": "123",
"eppno": "324"
}
]
},
{
"114-335": [
{
"edno": "100",
"eppno": "355"
},
{
"edno": "222",
"eppno": "999"
}
]
}
]
You could destructure the object to omit keys and build a single object with grouping keys. From this build an array of objects with a sinlge property.
const
data = [{ sourceno: "112", destno: "321", edno: "123", eppno: "322" }, { sourceno: "112", destno: "321", edno: "123", eppno: "324" }, { sourceno: "114", destno: "335", edno: "100", eppno: "355" }, { sourceno: "114", destno: "335", edno: "222", eppno: "999" }],
keys = ['sourceno', 'destno'],
result = Object
.entries(data.reduce((r, o) => {
const key = keys.map(k => {
let v;
({ [k]: v, ...o } = o);
return v;
}).join('-');
(r[key] ??= []).push(o);
return r;
}, {}))
.map(pair => Object.fromEntries([pair]));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A faster solution, compared to the one I proposed before, would be using an object to keep track of the items inserted in pdata; in this way you can achieve your goal traversing eddarr only once.
Please notice in the following code snippet I am using an IIFE to avoid "polluting" the global scope with the itemsListObj variable but that is not strictly necessary.
const eddarr = [{
"sourceno": "112",
"destno": "321",
"edno": "123",
"eppno": "322"
},
{
"sourceno": "112",
"destno": "321",
"edno": "123",
"eppno": "324"
},
{
"sourceno": "114",
"destno": "335",
"edno": "100",
"eppno": "355"
},
{
"sourceno": "114",
"destno": "335",
"edno": "222",
"eppno": "999"
}
];
const pdata = (function() {
const itemsListObj = {};
return eddarr.reduce((acc, { sourceno, destno, edno, eppno }) => {
const key = `${sourceno}-${destno}`;
const insertIndex = itemsListObj[key];
if (insertIndex != null) {
acc[insertIndex][key].push({ edno, eppno });
} else {
acc.push({ [key]: [{ edno, eppno }] });
itemsListObj[key] = acc.length - 1;
}
return acc;
}, []);
})()
console.log(pdata);
const values = {};
eddarr = [{ sourceno: "112", destno: "321", edno: "123", eppno: "322" }, { sourceno: "112", destno: "321", edno: "123", eppno: "324" }, { sourceno: "114", destno: "335", edno: "100", eppno: "355" }, { sourceno: "114", destno: "335", edno: "222", eppno: "999" }];
eddarr.map((entry) => {
var key = entry.sourceno + '-' + entry.destno;
if (!values[ key ]) { values[ key ] = []; }
values[ key ].push({
edno: entry.edno,
eppno: entry.eppno
})
});
console.log(Object.keys(values).map(key => { return { [ key ]: values[key] } }));