4

I'm reciving the next data

    [
      { id: "1", name: "test1", rName: "the1" },
      { id: "1", name: "test1", rName: "the2" },
      { id: "1", name: "test1", rName: "the3" },
      { id: "2", name: "test2", rName: "the1" },
      { id: "2", name: "test2", rName: "the2" },
      { id: "3", name: "test3", rName: "the1" }
    ]

I want to merge it by the id and push the rName's into an array to have this structure

    [
      { id: "1", name: "test1", rName: ["the1", "the2","the3"] },
      { id: "2", name: "test2", rName: ["the1", "the2"] },
      { id: "3", name: "test3", rName: ["the1"] }
    ]

I thought doing it with reduce but didn't succeed, if anyone can point me to the right direction it will be greatly appreciated.

Dangur
  • 139
  • 1
  • 7

5 Answers5

2

This is a pretty simple case of data reformatting. Code is below.

var data = [
  { id: "1", name: "test1", rName: "the1" },
  { id: "1", name: "test1", rName: "the2" },
  { id: "1", name: "test1", rName: "the3" },
  { id: "2", name: "test2", rName: "the1" },
  { id: "2", name: "test2", rName: "the2" },
  { id: "3", name: "test3", rName: "the1" }
];
    
var reduced = Object.values(data.reduce(function(accumulator, element) {
  if (!accumulator[element.id]) {
    accumulator[element.id] = { id: element.id, name: element.name, rName: [] };
  }
  
  accumulator[element.id].rName.push(element.rName);
  return accumulator;
}, {}));
console.log(reduced);

The accumulator checks if the key by element.id exists in the accumulator. If it does not, it creates it. It then pushes the new rName on the existing stack. Object.values() is then used to make the conversion back to an array.

pizzaisdavid
  • 455
  • 3
  • 13
Sébastien Renauld
  • 19,203
  • 2
  • 46
  • 66
1

You can use reduce and find like this:

In the reduce accumulator, check if there is already an item with same id as the current item being iterated. If yes, push the current item's rName to the rName array. Else, push a new item to the accumulator

var data = [
      { id: "1", name: "test1", rName: "the1" },
      { id: "1", name: "test1", rName: "the2" },
      { id: "1", name: "test1", rName: "the3" },
      { id: "2", name: "test2", rName: "the1" },
      { id: "2", name: "test2", rName: "the2" },
      { id: "3", name: "test3", rName: "the1" }
      ];

const newArray = data.reduce((acc, {id,name,rName}) => {
    const existing = acc.find(a => a.id == id);
    if (existing)
        existing["rName"].push(rName);
    else
        acc.push({id,name,rName: [rName]})
    return acc
}, []);

console.log(newArray)

This is a one line, code-golf answer. (Got the idea from @Sébastien's answer):

var data = [
  { id: "1", name: "test1", rName: "the1" },
  { id: "1", name: "test2", rName: "the2" },
  { id: "1", name: "test2", rName: "the3" },
  { id: "2", name: "test2", rName: "the1" },
  { id: "2", name: "test1", rName: "the2" },
  { id: "3", name: "test3", rName: "the1" }
]

const anotherArray = Object.values(data.reduce((acc, {id,name,rName}) =>
      ((acc[id] = acc[id] || {id,name,rName:[]})["rName"].push(rName), acc), {}));

console.log(anotherArray)
adiga
  • 34,372
  • 9
  • 61
  • 83
  • I like your answer, thank you for the explanation. Do you think there's a better way instead of reduce? – Dangur Dec 26 '18 at 10:13
  • Not sure what you mean by *better way*. If you don't want to use `reduce`, you could do the same thing with [forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) by declaring an `acc` array outside and doing the same logic of whatever is being done in `reduce`. – adiga Dec 26 '18 at 11:20
0

Pure ES6

let result = obj.reduce((acc, item) => {
  let found = acc.find(i => i.id === item.id);
  found ? (found.rName = [...found.rName, item.rName]) : (acc = [...acc, { ...item, rName: [item.rName] }]);
  return acc;
}, []);
Sumer
  • 2,687
  • 24
  • 24
0

If each id can determine a uniquename, this will work:

let data = [
  { id: "1", name: "test1", rName: "the1" },
  { id: "1", name: "test1", rName: "the2" },
  { id: "1", name: "test1", rName: "the3" },
  { id: "2", name: "test2", rName: "the1" },
  { id: "2", name: "test2", rName: "the2" },
  { id: "3", name: "test3", rName: "the1" }
];

let result = [];

for (let item of data) 
{
    const index = result.findIndex(i => i.id === item.id);
    if (index < 0) {
        result.push({ id: item.id, name: item.name, rName: [item.rName] });
    }
    else {
        result[index].rName.push(item.rName);
    }
}

Please note this will not work when following data should accept:

[
  { id: "1", name: "test1", rName: "the1" },
  { id: "1", name: "test2", rName: "the2" },
  { id: "1", name: "test2", rName: "the3" },
  { id: "2", name: "test2", rName: "the1" },
  { id: "2", name: "test1", rName: "the2" },
  { id: "3", name: "test3", rName: "the1" }
]
yuxxxxx
  • 1
  • 2
0

If you adhere to use method 'reduce', you can do like this:

var arr = [
        { id: "1", name: "test1", rName: "the1" },
        { id: "1", name: "test1", rName: "the2" },
        { id: "1", name: "test1", rName: "the3" },
        { id: "2", name: "test2", rName: "the1" },
        { id: "2", name: "test2", rName: "the2" },
        { id: "3", name: "test3", rName: "the1" }
    ]
    var arr1 = arr.reduce(function (a1, a2) {
        if (a1 instanceof Array) {
            let lastItem = a1[a1.length - 1]
            if (lastItem.id == a2.id) {
                lastItem.rName.push(a2.rName)
            } else {
                a1.push({ ...a2, rName: [a2.rName] })
            }
            return a1
        } else {
            let result = []
            if (a1.id == a2.id) {
                result.push({ ...a1, rName: [a1.rName, a2.rName] })
            } else {
                result.push({ ...a1, rName: [a1, rName] })
                result.push({ ...a2, rName: [a2, rName] })
            }
            return result

        }

    })
    console.log(JSON.stringify(arr1))

But I think you should do like this, for the code is more clear:

var arr = [
    { id: "1", name: "test1", rName: "the1" },
    { id: "1", name: "test1", rName: "the2" },
    { id: "1", name: "test1", rName: "the3" },
    { id: "2", name: "test2", rName: "the1" },
    { id: "2", name: "test2", rName: "the2" },
    { id: "3", name: "test3", rName: "the1" }
]
var map = new Map()
arr.forEach(function(item){
    if(map.has(item.id)){
        map.get(item.id).rName.push(item.rName)
    }else{
        map.set(item.id, {...item, rName: [item.rName]})
    }
})
var arr1 = Array.from(map.values())
console.log(JSON.stringify(arr1))
刘增光
  • 3
  • 3