1

I have an array like this:

[
    {
        group: "A",
        id: "1",
        name: "Mike"
    },
    {
        group: "A",
        id: "6",
        name: "Sherley"
    },
    {
        group: "B",
        id: "3",
        name: "Charlie"
    },
    {
        group: "C",
        id: "2",
        name: "Dave"
    }
]

and I want to group the array based on its group. The array is already sorted by group and name. So, I make something like this:

let lastgroup = c[0].group
return <Group title={lastgroup}>
    {c.map(x => {
        if (lastgroup == x.group) {
            return <a href={"#" + x.id}>{x.name}</a>
        } else {
            lastgroup = x.group
            return </Group><Group title={lastgroup}><a href={"#" + x.id}>{x.name}</a> //-> What should I put here for something like this?
        }
    })}
</Group>

Now, that solution above does not work obviously, and is not clean. How should I close and reopen Tag? Or is there a cleaner way to do that?

Thank you

Magician
  • 1,944
  • 6
  • 24
  • 38

2 Answers2

0

To clean the implementation up, I would suggest an intermediate process that groups sub-arrays via Array#reduce(), followed by a mapping over the Object#entries() of the reduced result where you would "wrap" items with the <Group /> tags.

The reduce step groups the data into an object, by the group key. Each grouping contains an array of items for that group (these items are JSX snippets "created" during the grouping stage).

The second step is mapping over entries of that "reduced object". This allows you to wrap <Group/> tags around the group items collected for each group during the prior reduce step, without the need for the lastgroup idea:

// Component state / data

var data = [
    {
        group: "A",
        id: "1",
        name: "Mike"
    },
    {
        group: "A",
        id: "6",
        name: "Sherley"
    },
    {
        group: "B",
        id: "3",
        name: "Charlie"
    },
    {
        group: "C",
        id: "2",
        name: "Dave"
    }
]

// Component render method

render() {

  return Object.entries(data
  .reduce((grouping, item) => {

    // Insert items for group if not present
    if( !grouping[ item.group ] ) {
        grouping[ item.group ] = [];
    }

    var groupItems = grouping[ item.group ];

    // Create each group item, as we build up the items for this group
    groupItems.push(<a href={"#" + item.id}>{item.name}</a>);

    return grouping;

  }, {}))
  .map((entry) => {

    // entry[0] is the group key, entry[0] is the group value (item array)
    const group = entry[0];
    const items = entry[1];

    // Wrap items of each group with <Group/> tags
    return <Group title={group}>{ items }</Group>
  })

}
Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
0

Step 1, group entries by attribute group. See How to group an array of objects by key for more information

const groups = data.reduce((reducer, current) => {
    reducer[current.group] = reducer[current.group] || []
    reducer[current.group].push(current)
    return reducer
}, {})
/* 
   console.log(groups)
   should give you
   { A:
       [ { group: 'A', id: '1', name: 'Mike' },
         { group: 'A', id: '6', name: 'Sherley' } 
     ],
     B: 
       [ { group: 'B', id: '3', name: 'Charlie' } ],
     C: 
       [ { group: 'C', id: '2', name: 'Dave' } ] 
    }
*/

Step 2, render the groups

const keys = Object.keys(groups)
return (<div>
    {keys.map(key => {
        const currentGroup = groups[key]
        // now render entries inside each group
        return (<Group key={key} title={key}>
            {currentGroup.map(entry => {
                return <a key={entry.id} href={`#${entry.id}`}>{entry.name}</a>
            })}
        </Group>)
    })}
</div>)
Rico Chen
  • 2,260
  • 16
  • 18