Concatenate json entry under the same name

Viewed 96

I'm currently trying to learn the basics of javascript and working with JSON.

I have a JSON file wherein I want to combine the imports of the same name into one entry. How would that be possible?

Raw JSON

[{
    "name": "1.date.17-Nov-18",
    "size": 1000,
    "imports": ["1.location.HOUSTON", "1.person.JOHN"]
},
{
    "name": "1.date.17-Nov-18",
    "size": 1000,
    "imports": ["1.location.MIAMI", "1.person.BEN", "1.person.JOHN"]
},
{
    "name": "1.date.18-Nov-18",
    "size": 1000,
    "imports": ["1.location.UBER", "1.person.JOHN"]
}
]

Expected output

[{
    "name": "1.date.17-Nov-18",
    "size": 1000,
    "imports": ["1.location.HOUSTON", "1.person.JOHN", "1.location.MIAMI", "1.person.BEN"]
},
{
    "name": "1.date.18-Nov-18",
    "size": 1000,
    "imports": ["1.location.UBER", "1.person.JOHN"]
}
]

Any tips and suggestions would be appreciated. Thank you very much.

4 Answers

Using an object to keep track of the names, we iterate through the data array using forEach.

Then we check if the name of the item has been passed before. If it has been passed, we merge their imports together. If not we add the item to the object.

To prevent duplicate imports, we use Set which prevents duplicate elements and then we convert it back to an array using the spread ... operator

And then we use Object.values to return the merged data without the names as keys

const result = {};
const data = [{"name":"1.date.17-Nov-18","size":1000,"imports":["1.location.HOUSTON","1.person.JOHN"]},{"name":"1.date.17-Nov-18","size":1000,"imports":["1.location.MIAMI","1.person.BEN","1.person.JOHN"]},{"name":"1.date.18-Nov-18","size":1000,"imports":["1.location.UBER","1.person.JOHN"]}];

data.forEach(item => {
  if (item.name in result) result[item.name].imports = [...new Set([...item.imports, ...result[item.name].imports])];
  else result[item.name] = item;
});

console.log(Object.values(result));

You can try this way.

const data = [{"name":"1.date.17-Nov-18","size":1000,"imports":["1.location.HOUSTON","1.person.JOHN"]},{"name":"1.date.17-Nov-18","size":1000,"imports":["1.location.MIAMI","1.person.BEN","1.person.JOHN"]},{"name":"1.date.18-Nov-18","size":1000,"imports":["1.location.UBER","1.person.JOHN"]}];

const result = data.reduce((acc, {name, size, imports}) => {
  acc[name] =  acc[name] || {name: name, size: size, imports: []};
  acc[name].imports = [...new Set([...acc[name].imports, ...imports])];
  
  return acc;
}, {})
console.log(Object.values(result));
.as-console-wrapper{min-height: 100%!important; top: 0}

Reduce the array into a Map and then make imports unique.

const data = [
  {
    name: '1.date.17-Nov-18',
    size: 1000,
    imports: ['1.location.HOUSTON', '1.person.JOHN'],
  },
  {
    name: '1.date.17-Nov-18',
    size: 1000,
    imports: ['1.location.MIAMI', '1.person.BEN', '1.person.JOHN'],
  },
  {
    name: '1.date.18-Nov-18',
    size: 1000,
    imports: ['1.location.UBER', '1.person.JOHN'],
  },
];

console.log(
  Array.from(data.reduce((m, o) => (
      m.has(o.name)
        ? m.get(o.name).imports.push(...o.imports)
        : m.set(o.name, { ...o }),
      m), new Map()).values(),
    (v) => ({ ...v, imports: [...new Set(v.imports)] }))
);

You can solve this by using Array.prototype.reduce. As you start learning JS so I write the answer more elaborately. Try this out-

const data = [{
    "name": "1.date.17-Nov-18",
    "size": 1000,
    "imports": ["1.location.HOUSTON", "1.person.JOHN"]
},
{
    "name": "1.date.17-Nov-18",
    "size": 1000,
    "imports": ["1.location.MIAMI", "1.person.BEN", "1.person.JOHN"]
},
{
    "name": "1.date.18-Nov-18",
    "size": 1000,
    "imports": ["1.location.UBER", "1.person.JOHN"]
}];

let res = data.reduce((acc, curr) => {
  if (acc[curr.name] === undefined) {
    // If not exists then take the original current object
    acc[curr.name] = curr;
  } else {
    // If exists then push the current imports to the previous imports
    acc[curr.name].imports.push(...curr.imports);
  }
  return acc;
}, {});

// Convert the object to array.
res = Object.values(res);

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

Related