Grouping by multiple fields per object
<p>I am trying to determine the best data-type to sort an array of objects, into groups defined by properties. I have an array of objects, like so:</p>

<pre><code>var people = [
    {
        name: 'Pete',
        gender: 'Male',
        age: 22

    },
    {
        name: 'Samantha',
        gender: 'Female',
        age: 20

    },
    {
        name: 'Frank',
        gender: 'Male',
        age: 22

    },
    {
        name: 'Gary',
        gender: 'Male',
        age: 21

    },
    {
        name: 'Maria',
        gender: 'Female',
        age: 20

    },
    {
        name: 'Hannah',
        gender: 'Female',
        age: 21

    },
    {
        name: 'Pete',
        gender: 'Male',
        age: 20

    }
];
</code></pre>

<p>I need to group these objects into an arbitrary-defined group. E.g.:</p>

<ol>
<li>Group 1: <code>gender</code></li>
<li>Group 2: <code>age</code></li>
</ol>

<p>(This can be defined by the server and can change to contain a third group if we wish.)</p>

<p>Which then gives me (visually):</p>

<pre><code>Male:
   21:
     Gary
   22:
     Pete
     Frank

Female
   20:
     Samantha
     Maria
   21:
     Hannah
</code></pre>

<p>I <em>think</em> the appropriate data type would be an object of objects. I.e.:</p>

<pre><code>{
    Male: {
        21: {
            [
                {
                    name: 'Gary',
                    gender: 'Male',
                    age: 21

                }
            ]
        },
        22: {
            [
                {
                    name: 'Pete',
                    gender: 'Male',
                    age: 22

                },
                {
                    name: 'Frank',
                    gender: 'Male',
                    age: 22

                }
            ]
        }
    },
    Female: {
        20: {
            [
                {
                    name: 'Samantha',
                    gender: 'Female',
                    age: 20

                },
                {
                    name: 'Maria',
                    gender: 'Female',
                    age: 20

                }
            ]
        },
        21: {
            [
                {
                    name: 'Hannah',
                    gender: 'Female',
                    age: 21

                }
            ]
        }
    }
}
</code></pre>

<p>But I cannot work out, for the life of me, an appropriate algorithm to sort these objects into a data-type which represents the above.</p>

<p>There is a useful utility in <code>underscore.js</code> called <code>_.groupBy(arr, callback)</code> which I can use as follows:</p>

<pre><code>_.groupBy(people, function (person) {
    var props = ['gender', 'age'], // server-defined
        prop = [];

    for (var i = 0, length = props.length; i &lt; length; i++) {
        prop.push(person[props[i]]);
    }

    return prop.join('|');
});
</code></pre>

<p>This gives me a 1-depth object which I can use a <code>for...in</code> loop to iterate over the keys, and loop through to build the object above, but it's that bit of the code I'm stuck on.</p>

<p>The returned object would be:</p>

<pre><code>{
    "Male|22": [
        {
            "name": "Pete",
            "gender": "Male",
            "age": 22
        },
        {
            "name": "Frank",
            "gender": "Male",
            "age": 22
        }
    ],
    "Female|20": [
        {
            "name": "Samantha",
            "gender": "Female",
            "age": 20
        },
        {
            "name": "Maria",
            "gender": "Female",
            "age": 20
        }
    ],
    "Male|21": [
        {
            "name": "Gary",
            "gender": "Male",
            "age": 21
        }
    ],
    "Female|21": [
        {
            "name": "Hannah",
            "gender": "Female",
            "age": 21
        }
    ],
    "Male|20": [
        {
            "name": "Pete",
            "gender": "Male",
            "age": 20
        }
    ]
}
</code></pre>

<p>I'm thinking of then looping through each key in the object, splitting at the pipe (<code>|</code>) and using recursion to construct a new object of objects containing the groups/array of data.</p>

<p>That's such a horrendous way of achieving this but I have no idea how to do it otherwise.</p>

<p>Is there a better way I'm missing?</p>