MattyRad MattyRad - 2 months ago 7
Javascript Question

Javascript, extract and organize an array of objects by properties

In short, I want to create a generic method "organize" to turn this:

[
{ name: 'band1', type: 'concert', subtype: 'rock' },
{ name: 'band2', type: 'concert', subtype: 'jazz' },
{ name: 'band3', type: 'concert', subtype: 'jazz' },
{ name: 'fun1', type: 'festival', subtype: 'beer' },
{ name: 'fun2', type: 'festival', subtype: 'food' },
]


into this:

{
'concert': {
'rock': [
{ name: 'band1', type: 'concert', subtype: 'rock' },
],
'jazz': [
{ name: 'band2', type: 'concert', subtype: 'jazz' },
{ name: 'band3', type: 'concert', subtype: 'jazz' }
]
},
'festival': {
'beer': [
{ name: 'fun1', type: 'festival', subtype: 'beer' },
],
'food': [
{ name: 'fun2', type: 'festival', subtype: 'food' },
]
}
}


from the signature:

organize(events, ['type', 'subtype']);


The reason I want to do this is to have a simple nested for loop to display the data. If you're familiar with Vue.js, it'll look like this:

<div v-for="(type, subtypes) in organize(events, ['type', 'subtype'])">
<h1>{{ type }}</h1>
<div v-for="(subtype, events) in subtypes">
<h2>{{ subtype }}</h2>
<div v-for="event in events">
<h3>{{ event.name }}</h3>
</div>
</div>
</div>


For me it's been a brain-bending exercise. I think it's ripe for recursion and some combination of
map
filter
reduce
, but I've spent too much time trying to think of a solution, and instead wrote some very ugly code to accomplish essentially the same thing. It's also possible that I'm not aware of some useful feature of javascript which could help me do this....

Advice or guidance would be appreciated, but it's not a pressing matter. I just think it'd be really useful to have a generic method to organize arrays as such.

Answer

I think this could be a correct implementation of organize:

function organize(rows, groupBy) {
    var last = groupBy.length - 1;
    return rows.reduce ( (res, obj) => {
        groupBy.reduce( (res, grp, i) => 
            res[obj[grp]] || (res[obj[grp]] = i == last ? [] : {}), res).push(obj);
        return res;
    }, {});
}

var events = [
    { name: 'band1', type: 'concert', subtype: 'rock' },
    { name: 'band2', type: 'concert', subtype: 'jazz' },
    { name: 'band3', type: 'concert', subtype: 'jazz' },
    { name: 'fun1', type: 'festival', subtype: 'beer' },
    { name: 'fun2', type: 'festival', subtype: 'food' },
];

var res = organize(events, ['type','subtype']);

console.log(res);

Comments