Jack The Baker
Jack The Baker

Reputation: 1893

Group array object by object property and add new key

I got an array and want to convert my array into new shape, something like what on html section, so I did it successfully, but there is a problem, and a question:

Question: can I use iteration once? I mean already used map with filter, is there a better way to do this? like use single function like filter or reduce without map ?

Problem: I want to change id key name to value and title to label, but looks like can't do this in filter() Also I used forEach and map and reduce and etc.. but didn't work.

let data = [{
    id: 1,
    group: 1,
    parent: 1,
    title: 'group a'
  }, {
    id: 2,
    group: 1,
    parent: null,
    title: 'a1'
  }, {
    id: 3,
    group: 1,
    parent: null,
    title: 'a2'
  }, {
    id: 4,
    group: 2,
    parent: null,
    title: 'b1'
  },
  {
    id: 5,
    group: 2,
    parent: 2,
    title: 'group b'
  }
];




let array = [];
data.map(function(item) {
  if (item.parent) {
    let obj = {};
    obj.label = item.title
    //obj.options = data.filter(x => !x.parent && x.group === item.parent);
    obj.options = data.map(x => !x.parent && x.group === item.parent ? {value: x.id, label: x.title} : {});
    array.push(obj)
  }
})

console.log(array);
<script> 
[{
  label: "group a",
  options: [{
      label: "a1",
      value: 1
    },
    {
      label: "a2",
      value: 2
    }
  ]
},
{
  label: "group b",
  options: [{
      label: "b1",
      value: 4
    }
  ]
}];
</script>

I tried this, and used short if condition but it will add empty object if condition is false:

obj.options = data.map(x => !x.parent && x.group === item.parent ? {value: x.id, label: x.title} : {});

Upvotes: 0

Views: 140

Answers (1)

Tushar Shahi
Tushar Shahi

Reputation: 20556

Your solution is not the ideal way to do this but if tweaked a little it can still be made to work. Just put a filter after your map condition to remove all the empty objects.

let data = [{
    id: 1,
    group: 1,
    parent: 1,
    title: 'group a'
  }, {
    id: 2,
    group: 1,
    parent: null,
    title: 'a1'
  }, {
    id: 3,
    group: 1,
    parent: null,
    title: 'a2'
  }, {
    id: 4,
    group: 2,
    parent: null,
    title: 'b1'
  },
  {
    id: 5,
    group: 2,
    parent: 2,
    title: 'group b'
  }
];




let array = [];
data.forEach(function(item) {
  if (item.parent) {
    let obj = {};
    obj.label = item.title
    obj.options = data.map(x => !x.parent && x.group === item.parent ? {value: x.id, label: x.title} : {}).filter(x => Object.keys(x).length > 0);
    array.push(obj)
    
  }
})

console.log(array);
<script> 
[{
  label: "group a",
  options: [{
      label: "a1",
      value: 1
    },
    {
      label: "a2",
      value: 2
    }
  ]
},
{
  label: "group b",
  options: [{
      label: "b1",
      value: 4
    }
  ]
}];
</script>

I have used Object.keys. Also map is when you want to transform the array into a new one. map returns an array, if you are not making use of the returned array, then map is not the ideal choice. That is why I used forEach.

Note:. The way to do this properly would be .reduce(). It is for computing a result from an array, where at each iteration you can refer to the accumulated object uptil that iteration.

Upvotes: 1

Related Questions