node_man
node_man

Reputation: 1449

remove nested foreach loops

In my code, I have used two forEach loops. But in order to optimize my code, I have been instructed not to use forEach loop inside a forEach loop. So I don't want to loop over the second array obj3. I just want to get the values at a certain position without using the inner forEach loop. Here is my code : -

var obj2 = [{
  "name": "4134",
  "calls": [

  ]
}]

    var obj3 = [{ Channel: 'SIP/4134-0004462a',
        State: 'Up',
        Accountcode: '7013658596'},
      { Channel: 'SIP/4334-sa',
        State: 'Up',
        Accountcode: '07717754702',
      }]


var function = (obj2, obj3) => {
    obj2.forEach((a) =>
      obj3.forEach((b) => {
        if (b.Channel.includes(a.name)) a.calls = (a.calls || []).concat(Object.assign({}, { MobileNo: b.Accountcode, Status : b.State}));

      })
    );
};

function(obj2, obj3);

The above code loops through obj2 and obj3 and if the value of the name key exist in the Channel key's value then it picks the Accountcode and State from obj3 and pushes them in the calls array of the obj2. Here is the output array:-

    [ {
  "name": "4134",
  "calls": [
    {
      "MobileNo": "7013658596",
      "Status": "Up"
    }
  ]
}]

What I have done so far

var func = (obj2, obj3) => {

var channelArr = [];
const Channels = obj3.reduce((acc, curVal) => {
  obj2.forEach((item)=>{
    if(curVal.Channel.includes(item.name)){
      item.calls.push({'MobileNo':curVal.Accountcode,'Status': curVal.State})
    }
  })
  return obj2;
}, [])

};

I tried doing it using reduce function but I'm really not sure if this can improve the performance. Please do let me know if you have better suggestions.

Upvotes: 3

Views: 1100

Answers (3)

yajiv
yajiv

Reputation: 2941

Hope this helps. I have created lookup table like structure with help of obj3. and after that when traversing obj2 just checking whether name is present in lookup table or not and if present then assign some object to calls

var obj2=[{name:"4134",calls:[]}],obj3=[{Channel:"SIP/4134-0004462a",State:"Up",Accountcode:"7013658596"},{Channel:"SIP/4334-sa",State:"Up",Accountcode:"07717754702"}];

var fun = (obj2, obj3) => {
  //creating temp object which conatin name as key and index as value from obj2
  var temp={};
  obj3.forEach((b,i)=>{
    var myRegexp = /\/(\d+)/g;
    var name=myRegexp.exec(b.Channel);
    temp[name[1]]=i;
  });
  
  obj2.forEach(a => {
    if(temp[a.name] !== undefined) {  //if temp object contain key then we need to merge this object
      var b = obj3[temp[a.name]];
      a.calls =  (a.calls || []).concat(Object.assign({}, { 
                     MobileNo: b.Accountcode, 
                     Status : b.State
                 }));
    }
  });
  console.log(obj2);
}
fun(obj2,obj3);

Upvotes: 1

Hardik Pithva
Hardik Pithva

Reputation: 1745

I tried using filter and map, check it out if this works for you.

const result = obj2.map(a => {
  const foundAll = obj3.filter(
    ({ Channel, Accountcode, State }) =>
      Channel.includes(a.name) && { Accountcode, State }
  );
  return {
    name: a.name,
    calls: [...a.calls, foundAll]
  };
});
console.info(result);

Find working Bin here.

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370689

Since the names are in a predictable location inside Channel, you can build an object indexed by names from the obj3 initially, and then just use bracket notation to get the array you need, O(n):

var obj2 = [{
  "name": "4134",
  "calls": [
  ]
}];
var obj3 = [{
    Channel: 'SIP/4134-0004462a',
    State: 'Up',
    Accountcode: '7013658596'
  },
  {
    Channel: 'SIP/4334-sa',
    State: 'Up',
    Accountcode: '07717754702',
  }
]

const objsByName = obj3.reduce((a, item) => {
  const { Channel } = item;
  const name = Channel.match(/\/(\d+)/)[1];
  if (!a[name]) a[name] = [];
  a[name].push(item);
  return a;
}, {});
obj2.forEach(({ name, calls }) => {
  calls.push(...objsByName[name]);
});
console.log(obj2);

Upvotes: 2

Related Questions