16

Im trying to create a collection like this in order to use in a react component:

let data = [
    { 
        group : 'A', 
        children : [
            { name : 'Animals', id : 22 },
            ...
        ]
    },
    { 
        group : 'B', children : [
            { name : 'Batteries', id : 7},
            { name : 'Baggage', id : 12 },
            ...
        ]
    },
    { 
        group : 'C', children : [
            { name : 'Cake', id : 7},
            ...
        ]
    },
]

 I've already sort my data like this :

let rawData = [
    { name : 'Animals', id : 10},
    { name : 'Batteries', id : 7},
    { name : 'Baggage', id : 12 },
    { name : 'Cake', id : 7},
    ...
]

Also I used this sorting method but the problem is, it's returning an Object with A, B, C keys with children as values. But I have to turn it into array like above in order to use that.

Here is what i've tried so far :

let data = rawData.reduce(function(prevVal, newVal){   
    char = newVal.name[0].toUpperCase();
    return { group: char, children :{name : newVal.name, id : newVal.id}};
},[])
Hesan Aminiloo
  • 418
  • 1
  • 4
  • 20

2 Answers2

44

You can create object with reduce and then use Object.values on that object.

let rawData = [
  { name : 'Animals', id : 10},
  { name : 'Batteries', id : 7},
  { name : 'Baggage', id : 12 },
  { name : 'Cake', id : 7},
]

let data = rawData.reduce((r, e) => {
  // get first letter of name of current element
  let group = e.name[0];
  // if there is no property in accumulator with this letter create it
  if(!r[group]) r[group] = {group, children: [e]}
  // if there is push current element to children array for that letter
  else r[group].children.push(e);
  // return accumulator
  return r;
}, {})

// since data at this point is an object, to get array of values
// we use Object.values method
let result = Object.values(data)

console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • Hi @NenadVracar, can you explain this a little more? Thanks in advance... – Gerben den Boer Mar 21 '19 at 14:32
  • @Gerben den Boer Updated the answer. – Nenad Vracar Mar 21 '19 at 15:05
  • @NenadVracar I think this does not sort the object alphabetically? or am i missing something – Onichan Oct 15 '19 at 10:42
  • Firstly, You need to sort your data by name. let data = rawData.sort((a, b) => a.name.localeCompare(b.name, 'es', { sensitivity: 'base' })).reduce(... – arturmoroz Nov 14 '20 at 07:27
  • 3
    on typescript i'm getting `Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'. No index signature with a parameter of type 'string' was found on type '{}'.ts(7053)` for `r[group]` – hakki Jun 30 '21 at 15:18
-1

in answer to @hakkikonu, for typescript add the type of outputed reducer when calling .reduce

 let data = rawData.reduce((r: any, e) => {
  let group = e.name[0];
  if (!r[group]) r[group] = { group, children: [e] }
  else r[group].children.push(e);
  return r;
}, {} );
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 13 '23 at 12:06