Home > OS >  Merge arrays matching a particular key value in JavaScript
Merge arrays matching a particular key value in JavaScript

Time:02-26

I have an array which is like this:

var arr = [{
  "date": "JAN",
  "value": 5,
  "weight": 3
}, {
  "date": "JAN",
  "value": 4,
  "weight": 23
}, {
  "date": "FEB",
  "value": 9,
  "weight": 1
}, {
  "date": "FEB",
  "value": 10,
  "weight": 30
}]

I want to match the primary key which is heredate. Matching this I want to merge the rest of the key values and get this following output:

[{
  "date": "JAN",
  "value": [5, 4],
  "weight": [3, 23]
}, {
  "date": "FEB",
  "value": [9, 10],
  "weight": [1, 30]
}]

I have written a function like this but can't figure out how to concat the key values:

var arr = [{
  "date": "JAN",
  "value": 5,
  "weight": 3
}, {
  "date": "JAN",
  "value": 4,
  "weight": 23
}, {
  "date": "FEB",
  "value": 9,
  "weight": 1
}, {
  "date": "FEB",
  "value": 10,
  "weight": 30
}]

const transform = (arr, primaryKey) => {
  var newValue = [];
  for (let i = 0; i < arr.length; i  ) {
    for (let j = 1; j < arr.length; j  ) {
      if (primaryKey[i] === primaryKey[j]) {
        newValue.push({
          ...arr[i],
          ...arr[j]
        });
      }
    }
  }
  return newValue
};

console.log(transform(arr,'date'))

CodePudding user response:

  • Using Array#reduce, iterate over the list while updating a Map where the key is the primary-key and the value is the grouped object. In every iteration, create/update the pair.
  • Using Map#values, return the list of grouped objects

const transform = (arr, primaryKey) => [...
  arr.reduce((map, { [primaryKey]: key, ...e }) => {
    const { [primaryKey]: k, ...props } = map.get(key) ?? {};
    for(let prop in e) {
      props[prop] = [...(props[prop] ?? []), e[prop]];
    }
    map.set(key, { [primaryKey]: key, ...props });
    return map;
  }, new Map)
  .values()
];

const arr = [ { "date": "JAN", "value": 5, "weight": 3 }, { "date": "JAN", "value": 4, "weight": 23 }, { "date": "FEB", "value": 9, "weight": 1 }, { "date": "FEB", "value": 10, "weight": 30 } ]; 
console.log( transform(arr, 'date') );

CodePudding user response:

The following code should work:

const transform = (arr, primaryKey) => {
    var newValue = [];
    for(let i = 0; i < arr.length; i  ){
        arr[i]["value"] = [arr[i]["value"]];
        arr[i]["weight"] = [arr[i]["weight"]];
    }
    newValue.push(arr[0])
    for(let i = 1; i < arr.length; i  ){
        let contains = false;
        for(let j = 0; j < newValue.length; j  ){
            if(newValue[j][primaryKey] == arr[i][primaryKey]){
                newValue[j]["value"].push(arr[i]["value"][0]);
                newValue[j]["weight"].push(arr[i]["weight"][0]);
                contains = true;
            }
        }
        if(!contains){
            newValue.push(arr[i]);
        }
        
    }
   return newValue
};

var arr = [{
              "date": "JAN",
              "value": 5,
              "weight": 3
          }, {
              "date": "JAN",
              "value": 4,
              "weight": 23
          }, {
              "date": "FEB",
              "value": 9,
              "weight": 1
          }, {
              "date": "FEB",
              "value": 10,
              "weight": 30
          }] 
          
var newthing = transform(arr,"date");
console.log(newthing);

Output:

[ { date: 'JAN', value: [ 5, 4 ], weight: [ 3, 23 ] },
  { date: 'FEB', value: [ 9, 10 ], weight: [ 1, 30 ] } ]

The way this code works is that first, we turn the values of the keys for "value" and "weight" into lists.

Then, we begin by pushing the first element of arr into newValue.

From here, we do a nested for loop to iterate through the remaining of arr and newValue:

If the value of "date" for every element of arr already exists in newValue, then we will push in the values of "value" and "weight" that belongs to arr.

However, if it does not exist, then we will simply push that element inside of newValue.

I hope this helped answer your question! Pleas let me know if you need any further help or clarification :)

CodePudding user response:

Combining a couple of reduce can also do the same job:

const arr = [{
              "date": "JAN",
              "value": 5,
              "weight": 3
          }, {
              "date": "JAN",
              "value": 4,
              "weight": 23
          }, {
              "date": "FEB",
              "value": 9,
              "weight": 1
          }, {
              "date": "FEB",
              "value": 10,
              "weight": 30
          }] 

const arrayMappedByDate = arr.reduce((acc, curData) => {
  if (acc[curData.date]) {
    acc[curData.date].push(curData)
  } else {
    acc[curData.date] = [curData]
  }
  return acc
}, {})

const transformedArray = Object.entries(arrayMappedByDate).map(([dateInit, data]) => {
 const normalized = data.reduce((acc, cur) => {
   if (acc.date) {
     acc.value.push(cur.value)
     acc.weight.push(cur.weight)
   } else {
     acc = { 
       date: cur.date,
       value: [cur.value],
       weight: [cur.weight]
     }
   }
   return acc
 }, {})
 return { [dateInit]: normalized }
})


 console.log(transformedArray)
  • Related