1

Example of the object data I am dealing with

var myData = [{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}]

I am trying to figure out the easiest way to group them by interests. I am open to using lodash or underscore, but I cannot get the final result to look like this....

I want this to be the output:

[{ "Baseball" : [{
                  "name": "John",
                  "age" : 30
                 },
                 {
                  "name" : "Bob",
                  "age" : 21
                 }]
 },
 { "Tennis" : [{
                 "name" : "Sally",
                 "age" : 21
               }]
 }];

Basically, each interest becomes a new object key containing all of the matched values within arrays.

I am having trouble constructing this output. Any assistance would be greatly appreciated. I prefer to use lodash/underscore to keep things very easy.

Thank you!

2
  • 3
    You want the result to be an array of objects that each have a different key? That seems inconvenient. Why not have the result be an object? {Baseball: [...], Tennis: [...]} Commented Mar 7, 2017 at 22:30
  • That could be fine. I just need to have each of the objects grouped to the correct key. That would be fine. I am open to the most streamlined way. Commented Mar 7, 2017 at 22:31

4 Answers 4

2

You could use Array.reduce for this:

var myData = [
{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}];

var result = myData.reduce(function(entities, obj) {
   entities[obj.interest] = (entities[obj.interest] || []).concat({
      name: obj.name,
      age: obj.age
   });
   return entities;
}, {});
console.log(result);

A little bit more general approach:

function groupBy(data, key, tFunc) {
   mapFunc = (typeof tFunc === "function")? tFunc: function(o) { return o };
   return (Array.isArray(data)?data:[]).reduce(function(entities, o) {
     if(o[key]) {
       entities[o[key]] = (entities[o[key]] || []).concat(tFunc(o));
     }
     return entities;
   }, {});
}


// test code
var myData = [
{
  "name": "John",
  "age": 30,
  "interest": "Baseball"
},
{
  "name": "Bob",
  "age": 21,
  "interest": "Baseball"
},
{
  "name" : "Sally",
  "age" : 29,
  "interest": "Tennis"
}];

var result = groupBy(myData, "interest", function(o) { return { name: o.name, age: o.age}});
console.log(result);
var result2 = groupBy(myData, "age", function(o) { return o.name});
console.log(result2);

Sign up to request clarification or add additional context in comments.

Comments

2

A group-by operation can be done by matching values in a dictionary (hashtable). In JavaScript all objects are dictionaries with property-names as the keys, for values we use arrays.

For example (press the "Run code snippet" button below to see the results):

function groupBy( input, propertyName ) {
    
    var output = {};
    for(var i = 0; i < input.length; i++) {
        
        var groupByValue = input[i][propertyName];
        if( !(groupByValue in output) ) {
            output[ groupByValue ] = [];
        }

        var dolly = cloneObjectButIgnoreProperty( input[i], propertyName );
        output[ groupByValue ].push( dolly );
    }

    return output;
}

function cloneObjectButIgnoreProperty( value, ignorePropertyName ) {
    
    var dolly = {};
    var propertyNames = Object.keys( value );
    for( var i = 0; i < propertyNames .length; i++ ) {
        var propertyName = propertyNames[i];
        if( propertyName == ignorePropertyName ) continue;
        dolly[propertyName ] = value[propertyName ];
    }
    return dolly;
}

var myData = [
    {
        "name": "John",
        "age": 30,
        "interest": "Baseball"
    },
    {
        "name": "Bob",
        "age": 21,
        "interest": "Baseball"
    },
    {
        "name" : "Sally",
        "age" : 29,
        "interest": "Tennis"
    }
];

var groupedByInterest = groupBy( myData, 'interest' );
console.log( "By interest:" );
console.log( groupedByInterest );

var groupedByName = groupBy( myData, 'name' );
console.log( "By name:" );
console.log( groupedByName );

var groupedByAge = groupBy( myData, 'age' );
console.log( "By age:" );
console.log( groupedByAge  );

5 Comments

@AndrewLi The OP said in a comment-reply: " I just need to have each of the objects grouped to the correct key. That would be fine. I am open to the most streamlined way." - so I believe my answer is correct, especially as my code preserves the original input objects (instead of cloning them or removing properties) so it will have less memory usage.
I tested this snippet, it kinda works, but not exactly.
@Kinduser—"…and uses old patterns". Heaven forbid that code should be clear, easy to maintain and compatible with host versions beyond nightlies.
His solution is fine and better readable for people who are new to JS, but he missed a transform function to transform the objects to get rid of the unwanted "interest" key.
@cyrix I've added a function that clones the object and removes the specified property.
0

The solution using Array.prototype.reduce() function:

var myData = [{ "name": "John", "age": 30, "interest": "Baseball" }, { "name": "Bob", "age": 21,     "interest": "Baseball" }, { "name" : "Sally", "age" : 29, "interest": "Tennis" }],

    result = myData.reduce(function (r, o) {
        r[o.interest] = r[o.interest] || [];
        r[o.interest].push({name: o.name, age: o.age});
        return r;
    }, {});

console.log(result);

Comments

0

var myData = [{name:"John",age:30,interest:"Baseball"},{name:"Bob",age:21,interest:"Baseball"},{name:"Sally",age:29,interest:"Tennis"}],
    result = [],
    interests = [...new Set(myData.map(v => v.interest))];
    
    interests.forEach(v => result.push({ [v] : [] }));
    myData.forEach((v,i) => result.forEach((c,i) => Object.keys(c)[0] == v.interest ? result[i][v.interest].push({name: v.name, age: v.age}) : c))
    console.log(result);

2 Comments

I think the OP wanted name and age keys
@AndrewLi It's fine now, I think.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.