how to group array of objects by value in reactjs / javascript
Asked Answered
A

4

10

I have an array of object that have different values like

 items=[{id:1,category:"cat_1" , title:"My title 1"},{id:2,category:"cat_2" , title:"My title 2"},{id:6,category:"cat_1" , title:"Another title 1"},{id:1,category:"cat_3" , title:"My title 3"},{id:8,category:"cat_1" , title:"Third Title"},{id:2,category:"cat_2" , title:"Another title 2 "}]

I use array map to list the object and display them as

     {
     items.map((item) => (
        <h1>{item.category}</h1>
        <p>{item.title}</p>
    ))} 

My question is how do i iterate the item so as it groups the items by category as follows

cat_1
- My title 1
- Another title 1
- My title 3

cat_2
- My title 2
- Another title 2

cat_3
-Third Title
Arsphenamine answered 24/3, 2018 at 7:0 Comment(0)
B
29

Use .reduce:

const items = [{
  id: 1,
  category: "cat_1",
  title: "My title 1"
}, {
  id: 2,
  category: "cat_2",
  title: "My title 2"
}, {
  id: 6,
  category: "cat_1",
  title: "Another title 1"
}, {
  id: 1,
  category: "cat_3",
  title: "My title 3"
}, {
  id: 8,
  category: "cat_1",
  title: "Third Title"
}, {
  id: 2,
  category: "cat_2",
  title: "Another title 2 "
}];
const cats = items.reduce((catsSoFar, { category, title }) => {
  if (!catsSoFar[category]) catsSoFar[category] = [];
  catsSoFar[category].push(title);
  return catsSoFar;
}, {});
console.log(cats);
Bookstand answered 24/3, 2018 at 7:3 Comment(6)
@TerryLennox: That is an understatement! In fact, reduce is a general iteration operation, everything you can do with a FOREACH loop (for/in, for/of, Array.prototype.forEach), you can do with reduce! Once you have reduce, you no longer need map, filter, groupBy, sort, etc. (except for readability and clarity, of course). There is a simple sketch of a proof on the Wikipedia page for fold. So, reduce is not just "super powerful", it is in fact "all-powerful".Towards
@JörgWMittag, but you could say the same thing about forEach and even plain for and map - the important part isn't using something that's sufficiently powerful ( qr.ae/RNMEGA ), but using something that's powerful enough and is semantically proper for what its effect is.Bookstand
Well put @Jörg I'll check out the article!Pest
@CertainPerformance: map is not general. It cannot change the length of the collection, for example, or return something that is not a collection. You cannot implement sum in terms of map, unless you abuse the fact that in ECMAScript, the mapping function can have side-effects and get access to the collection itself, thus mutating it.Towards
@JörgWMittag My point was that you can use/abuse (for example) map to achieve something that's not maplike, just like you can use/abuse reduce to do something more suited to a method such as forEach filter etc.Bookstand
for reducers with Object destructuring +1Expostulatory
C
5

I use lodash in a lot of projects as a general utility belt. If you decide to do something similar -- it would be simple as:

const data = [{
  id: 1,
  category: "cat_1",
  title: "My title 1"
}, {
  id: 2,
  category: "cat_2",
  title: "My title 2"
}, {
  id: 6,
  category: "cat_1",
  title: "Another title 1"
}, {
  id: 1,
  category: "cat_3",
  title: "My title 3"
}, {
  id: 8,
  category: "cat_1",
  title: "Third Title"
}, {
  id: 2,
  category: "cat_2",
  title: "Another title 2 "
}];

const groups = _.groupBy(data,  'category');

console.log(groups);
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lodash.min.js"></script>
Consanguineous answered 24/3, 2018 at 7:32 Comment(0)
S
2

I would make CertainPerformance's answer a bit more concise:

    const items = [{
      id: 1,
      category: "cat_1",
      title: "My title 1"
    }, {
      id: 2,
      category: "cat_2",
      title: "My title 2"
    }, {
      id: 6,
      category: "cat_1",
      title: "Another title 1"
    }, {
      id: 1,
      category: "cat_3",
      title: "My title 3"
    }, {
      id: 8,
      category: "cat_1",
      title: "Third Title"
    }, {
      id: 2,
      category: "cat_2",
      title: "Another title 2 "
    }];
    const cats = items.reduce((catMemo, { category, title }) => {
      (catMemo[category] = catMemo[category] || []).push(title);
      return catMemo;
    }, {});
    console.log(cats);
Stu answered 24/3, 2018 at 7:38 Comment(1)
how to render this in reactHegemony
R
0

Readability is important, but for anyone who's looking for a one-liner:

const groupedItems = items.reduce((ob, item) => ({...ob, [item.category]: [...ob[item.category] ?? [], item]}), {})
Ranice answered 29/12, 2023 at 19:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.