Anirudh Chhabra
Anirudh Chhabra

Reputation: 35

Merge Map data within an Array in javascript

Here is my current Array looks like:

{ entity: 'A', type: 'request', requestUrl: 'val1' },
{ entity: 'A', type: 'response', responseUrl: 'val1' },
{ entity: 'B', type: 'request', requestUrl: 'val1' },
{ entity: 'B', type: 'response', responseUrl: 'val1' },
{ entity: 'C', type: 'request', requestUrl: 'val1' },
{ entity: 'C', type: 'response', responseUrl: 'val1' },
{ entity: 'D', type: 'request', requestUrl: 'val1' },
{ entity: 'D', type: 'response', responseUrl: 'val1' },
{ entity: 'DADA', type: '', responseUrl: 'val1' }

Each row contains an attribute named 'entity' which has 2 rows : one corresponding to request and other corresponding to response. I need to merge the request and response rows, and have the data as one row only. (The attribute 'type' doesn't matter in the merged row, but need to have all other attributes). So the solution would be something like:

[{"entity":"A","type":"response","requestUrl":"val1","responseUrl":"val1"},
{"entity":"B","type":"response","requestUrl":"val1","responseUrl":"val1"},
{"entity":"C","type":"response","requestUrl":"val1","responseUrl":"val1"},
{"entity":"D","type":"response","requestUrl":"val1","responseUrl":"val1"}]

Currently, this is what I have: https://www.w3schools.com/code/tryit.asp?filename=FUHGQN2JON75

Not sure if that's the best way to do it. Recommendations welcome on how to improve this solution.

Thanks.

Upvotes: 3

Views: 2410

Answers (7)

brk
brk

Reputation: 50291

Use reduce to create a new array. But at the same time the out put should be checked if the order of the objects are changed in the array.

Let us consider these two objects

{ entity: 'A', type: 'request', requestUrl: 'val1' },
{ entity: 'A', type: 'response', responseUrl: 'val1' }

Consider the first object , and in this object we will check which key is present in second object but now in the first object then add that key in the first object.

let orgArray = [{
    entity: 'A',
    type: 'response',
    responseUrl: 'val1'
  },
  {
    entity: 'A',
    type: 'request',
    requestUrl: 'val1'
  },
  {
    entity: 'B',
    type: 'request',
    requestUrl: 'val1'
  },
  {
    entity: 'B',
    type: 'response',
    responseUrl: 'val1'
  },
  {
    entity: 'C',
    type: 'request',
    requestUrl: 'val1'
  },
  {
    entity: 'C',
    type: 'response',
    responseUrl: 'val1'
  },
  {
    entity: 'D',
    type: 'request',
    requestUrl: 'val1'
  },
  {
    entity: 'D',
    type: 'response',
    responseUrl: 'val1'
  },
  {
    entity: 'DADA',
    type: '',
    responseUrl: 'val1'
  }
]



let newArray = orgArray.reduce(function(acc, curr) {
  //get the index of the object where entity matches
  let getIndexOfEntity = acc.findIndex(function(item) {
    return item.entity === curr.entity
  })
  //if there is no such entity then it will give -1
  if (getIndexOfEntity === -1) {
    // in that case push the object
    acc.push(curr)
  } else {
    // if entity exist 
    //now check which key is missing from the
    // getting all the keys from both the object
    let getAllKeyFromAccObj = Object.keys(acc[getIndexOfEntity]);
    let getAllKeyFromCurrObj = Object.keys(curr)
    // looping through the key and adding the missing key 
    getAllKeyFromCurrObj.forEach(function(item) {
      if (getAllKeyFromAccObj.indexOf(item) === -1) {
        acc[getIndexOfEntity][item] = curr[item]
      }

    })
  }
  return acc;
}, [])

console.log(newArray)

Upvotes: 0

Prasanna
Prasanna

Reputation: 4636

Assuming request and response are consecutive we can just use spread operators for merging

const data = [{ entity: 'A', type: 'request', requestUrl: 'val1' },
{ entity: 'A', type: 'response', responseUrl: 'val1' },
{ entity: 'B', type: 'request', requestUrl: 'val1' },
{ entity: 'B', type: 'response', responseUrl: 'val1' },
{ entity: 'C', type: 'request', requestUrl: 'val1' },
{ entity: 'C', type: 'response', responseUrl: 'val1' },
{ entity: 'D', type: 'request', requestUrl: 'val1' },
{ entity: 'D', type: 'response', responseUrl: 'val1' },
{ entity: 'DADA', type: '', responseUrl: 'val1' }]

const newData = data.reduce((acc, item, index) => {
  if (index % 2 || !item.type) return acc;
  acc.push({...item, ...data[index+1]})
  return acc;
}, [])

console.log(newData)

Upvotes: 0

Mohammad Usman
Mohammad Usman

Reputation: 39322

You can use Map and forEach():

let data = [{ entity: 'A', type: 'request', requestUrl: 'val1' },{ entity: 'A', type: 'response', responseUrl: 'val1' },{ entity: 'B', type: 'request', requestUrl: 'val1' },{ entity: 'B', type: 'response', responseUrl: 'val1' },{ entity: 'C', type: 'request', requestUrl: 'val1' },{ entity: 'C', type: 'response', responseUrl: 'val1' },{ entity: 'D', type: 'request', requestUrl: 'val1' },{ entity: 'D', type: 'response', responseUrl: 'val1' }];

let result = ((a, m) => {
  a.forEach(o => {
    m.set(o.entity, Object.assign((m.get(o.entity) || {}), o));
  });
  return [...m.values()];
})(data, new Map());

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 0

Niekert
Niekert

Reputation: 947

You can use a Map for this that keeps track of all your entity objects.

Later you can convert the Map back to an array.

const input = [
  { entity: 'A', type: 'request', requestUrl: 'val1' },
  { entity: 'A', type: 'response', responseUrl: 'val1' },
  { entity: 'B', type: 'request', requestUrl: 'val1' },
  { entity: 'B', type: 'response', responseUrl: 'val1' },
  { entity: 'C', type: 'request', requestUrl: 'val1' },
  { entity: 'C', type: 'response', responseUrl: 'val1' },
  { entity: 'D', type: 'request', requestUrl: 'val1' },
  { entity: 'D', type: 'response', responseUrl: 'val1' },
  { entity: 'DADA', type: '', responseUrl: 'val1' }
]

const entityMap = new Map();
input.forEach(element => {
  let currentEntity = entityMap.get(element.entity) || {};

  entityMap.set(element.entity, {
    ...currentEntity,
    ...element,
  })
});

return Array.from(entityMap.values());

Upvotes: 0

аlex
аlex

Reputation: 5698

You can use this answer

var arr = [{ entity: 'A', type: 'request', requestUrl: 'val1' },
{ entity: 'A', type: 'response', responseUrl: 'val1' },
{ entity: 'B', type: 'request', requestUrl: 'val1' },
{ entity: 'B', type: 'response', responseUrl: 'val1' },
{ entity: 'C', type: 'request', requestUrl: 'val1' },
{ entity: 'C', type: 'response', responseUrl: 'val1' },
{ entity: 'D', type: 'request', requestUrl: 'val1' },
{ entity: 'D', type: 'response', responseUrl: 'val1' },
{ entity: 'DADA', type: '', responseUrl: 'val1' }];

var res = Array.from(
  new Set(arr.filter(x => x.type).map(x=>x.entity))
)
.map(el => arr.find(obj => obj.entity === el))

console.log(res);// 
/* 
[{"entity":"A","type":"request","requestUrl":"val1"},
{"entity":"B","type":"request","requestUrl":"val1"},
{"entity":"C","type":"request","requestUrl":"val1"},
{"entity":"D","type":"request","requestUrl":"val1"}]
*/

Upvotes: 0

Eddie
Eddie

Reputation: 26844

One option is to use reduce to group your array into an object. Use the entity as the key. Use Object.assign to convert the objects. Use Object.values to convert the object into an array.

var arr = [{"entity":"A","type":"request","requestUrl":"val1"},{"entity":"A","type":"response","responseUrl":"val1"},{"entity":"B","type":"request","requestUrl":"val1"},{"entity":"B","type":"response","responseUrl":"val1"},{"entity":"C","type":"request","requestUrl":"val1"},{"entity":"C","type":"response","responseUrl":"val1"},{"entity":"D","type":"request","requestUrl":"val1"},{"entity":"D","type":"response","responseUrl":"val1"},{"entity":"DADA","type":"","responseUrl":"val1"}];

var result = Object.values(arr.reduce((c, v) => {
  c[v.entity] = Object.assign(c[v.entity] || {}, v);
  return c;
}, {}));

console.log(result);

Upvotes: 2

Ankit Agarwal
Ankit Agarwal

Reputation: 30739

You can use Array.reduce() for that:

var arr = [{ entity: 'A', type: 'request', requestUrl: 'val1' },
{ entity: 'A', type: 'response', responseUrl: 'val1' },
{ entity: 'B', type: 'request', requestUrl: 'val1' },
{ entity: 'B', type: 'response', responseUrl: 'val1' },
{ entity: 'C', type: 'request', requestUrl: 'val1' },
{ entity: 'C', type: 'response', responseUrl: 'val1' },
{ entity: 'D', type: 'request', requestUrl: 'val1' },
{ entity: 'D', type: 'response', responseUrl: 'val1' },
{ entity: 'DADA', type: '', responseUrl: 'val1' }];
var res = arr.reduce((acc, item)=>{
  var existObj = acc.find(obj => obj.entity === item.entity);
  if(!existObj){
    acc.push(item);
  } else {
     existObj['responseUrl'] = item.responseUrl;
  }
  return acc;
}, []);
console.log(res);

Upvotes: 0

Related Questions