Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert JSON format (Group by)

I have JSON object like this:

[{
    "name" : "cat",
    "value" : 17,
    "group" : "animal",
},
 {
    "name" : "dog",
    "value" : 6,
    "group" : "animal",
},
 {
    "name" : "snak",
    "value" : 2,
    "group" : "animal",
},
{
    "name" : "tesla",
    "value" : 11,
    "group" : "car",
},
{
    "name" : "bmw",
    "value" : 23,
    "group" : "car",
}]

I want to convert this JSON to below format by JS:

[{
  "name":"animal",
  "children":[
     {"name":"cat", "value":17},
     {"name":"dog", "value":6},
     {"name":"snak", "value":2}
]},
{
  "name":"car",
  "children":[
     {"name":"bmw", "value":11},
     {"name":"tesla", "value":23}
]}]

I try to convert and filter by Reduce function but I couldn't convert to this format.

EDIT:

The code I tested was this.

let groupBy = function(xs, key) {
    return xs.reduce(function(rv, x) {
    (rv[x[key]] = rv[x[key]] || []).push(x);
    return rv;
    }, {});
};

let groubedByExchange=groupBy(JSON_data, 'group');
like image 523
Arman Feyzi Avatar asked Feb 18 '19 22:02

Arman Feyzi


4 Answers

You could build an array and search for the same group in the array.

var array = [{ name: "cat", value: 17, group: "animal" }, { name: "dog", value: 6, group: "animal" }, { name: "snak", value: 2, group: "animal" }, { name: "tesla", value: 11, group: "car" }, { name: "bmw", value: 23, group: "car" }],
    result = array.reduce((r, { group: name, ...object }) => {
        var temp = r.find(o => o.name === name);
        if (!temp) r.push(temp = { name, children: [] });
        temp.children.push(object);
        return r;
    }, []);
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 55
Nina Scholz Avatar answered Oct 19 '22 09:10

Nina Scholz


A simple solution is to build an intermediate dictonary and then transform it to your output structure.

You can use Array.reduce(), Object.entries() and Array.map() to do it:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) => {
  acc[group] = (acc[group] || []);
  acc[group].push({ name, value });
  return acc;
}, {})).map(([key, value]) => ({ name: key, children: value }));

console.log(result);

Using the spread operator makes it one line shorter and still readable:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) => {
  acc[group] = [...(acc[group] || []), { name, value }];
  return acc;
}, {})).map(([key, value]) => ({ name: key, children: value }));

console.log(result);

And one liner shorter with the comma operator:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) =>
  (acc[group] = [...(acc[group] || []), { name, value }], acc)
, {})).map(([key, value]) => ({ name: key, children: value }));

console.log(result);

The same can be done with Object.assign():

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const result = Object.entries(data.reduce((acc, { name, value, group }) =>
  Object.assign(acc, { [group]: [...(acc[group] || []), { name, value }] })
, {})).map(([key, value]) => ({ name: key, children: value }));

console.log(result);

And finally, a bit longer but with a reusable groupBy function:

const data = [
  { "name" : "cat", "value" : 17, "group" : "animal" },
  { "name" : "dog", "value" : 6, "group" : "animal" },
  { "name" : "snak", "value" : 2, "group" : "animal" },
  { "name" : "tesla", "value" : 11, "group" : "car" },
  { "name" : "bmw", "value" : 23, "group" : "car" }
];

const groupBy = prop => data => {
  return data.reduce((dict, item) => {
    const { [prop]: _, ...rest } = item;
    dict[item[prop]] = [...(dict[item[prop]] || []), rest];
    return dict;
  }, {});
};

const result = Object.entries(groupBy('group')(data))
  .map(([key, value]) => ({ name: key, children: value }));

console.log(result);
like image 32
jo_va Avatar answered Oct 19 '22 09:10

jo_va


Using Array#from, Array#reduce, Array#concat, destructuring, spread syntax and Map.

  1. reorganize your data structure by using Map
  2. restructuring your data using .map

const data=[{"name":"cat","value":17,"group":"animal",},{"name":"dog","value":6,"group":"animal",},{"name":"snak","value":2,"group":"animal",},{"name":"tesla","value":11,"group":"car",},{"name":"bmw","value":23,"group":"car",}];

const res = Array.from(
  data.reduce((a,{group, ...rest})=>{
    return a.set(group, [rest].concat(a.get(group)||[]));
  }, new Map())
).map(([group, children])=>({group,children}));

console.log(res);
like image 30
kemicofa ghost Avatar answered Oct 19 '22 10:10

kemicofa ghost


const arr = [{
    "name": "cat",
    "value": 17,
    "group": "animal",
  },
  {
    "name": "dog",
    "value": 6,
    "group": "animal",
  },
  {
    "name": "snak",
    "value": 2,
    "group": "animal",
  },
  {
    "name": "tesla",
    "value": 11,
    "group": "car",
  },
  {
    "name": "bmw",
    "value": 23,
    "group": "car",
  }
]

const newFormat = arr.reduce((pre, cur) => {
  const group = pre.find(grp => grp.name === cur.group)
  if (group) {
    group.children.push({
      name: cur.name,
      value: cur.value
    })
    return pre
  }

  const newGroup = {
    name: cur.group,
    children: [{
      name: cur.name,
      value: cur.value
    }]
  }
  pre.push(newGroup)
  return pre
}, [])

console.log(newFormat)

there you go. first you try to find that group in new array, if it exists you add that child to it. if not, you create the group and children array and push it to the array

like image 2
fila90 Avatar answered Oct 19 '22 09:10

fila90