2

i have a array with objects in it. I need to create multiple arrays with objects grouped by one of the properties value. To clarify here is my array:

var people = [
    new Person("Scott", "Guthrie", 38),
    new Person("Scott", "Johns", 36),
    new Person("Scott", "Hanselman", 39),
    new Person("Jesse", "Liberty", 57),
    new Person("Jon", "Skeet", 38)
];

I want to have one array with all the people with first name Scott, one with all with the first name Jesse and so on. Any suggestions will be helpful.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
user3377947
  • 45
  • 2
  • 4
  • 1
    Have a look at: [`Array.prototype.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) or [`Array.prototype.reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) – Andreas Jan 16 '16 at 09:32

2 Answers2

4

To do that, you can loop through the array entries (in any of several ways, let's use forEach here) and create an object or Map keyed by the names you come across, with the value being the arrays of entries for those names.

Here's an example using an object:

// Create an object with no prototype, so it doesn't have "toString"
// or "valueOf", although those would be unlikely names for people to have
var nameArrays = Object.create(null);

// Loop the people array
people.forEach(function(person) {
    // Get the name array for this person's name, if any
    var nameArray = nameArrays[person.firstName];
    if (!nameArray) {
        // There wasn't one, create it
        nameArray = nameArrays[person.firstName] = [];
    }
    // Add this entry
    nameArray.push(person);
});

Live Example:

function Person(firstName, lastName, age) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
}
var people = [
  new Person("Scott", "Guthrie", 38),
  new Person("Scott", "Johns", 36),
  new Person("Scott", "Hanselman", 39),
  new Person("Jesse", "Liberty", 57),
  new Person("Jon", "Skeet", 38)
];

// Create an object with no prototype, so it doesn't have "toString"
// or "valueOf", although those would be unlikely names for people to have
var nameArrays = Object.create(null);

// Loop the people array
people.forEach(function(person) {
  // Get the name array for this person's name, if any
  var nameArray = nameArrays[person.firstName];
  if (!nameArray) {
    // There wasn't one, create it
    nameArray = nameArrays[person.firstName] = [];
  }
  // Add this entry
  nameArray.push(person);
});

// Show results
Object.keys(nameArrays).sort().forEach(function(firstName) {
  snippet.log(
    "People named " + firstName +
    ": " +
    nameArrays[firstName].map(function(person) {
      return person.firstName + " " + person.lastName;
    }).join(", ")
  );
});
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

ES2015 adds Maps to the language, so in an ES2015 environment we might use a Map rather than an object for our nameArrays:

// Creating the map:
let nameArrays = new Map();

// Getting an array:
nameArray = nameArrays.get(person.firstName);

// Adding an array:
nameArrays.set(person.firstName, []);

// Looping through the map:
for (let [firstName, nameArray] of nameArrays) {
    // Use `firstName` and `nameArray` here
}
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
2

This is a more generic solution. getGroupedBy(persons, key) returns an array of arrays with the grouped persons by the key.

function Person(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
}

var people = [
    new Person("Scott", "Guthrie", 38),
    new Person("Scott", "Johns", 36),
    new Person("Scott", "Hanselman", 39),
    new Person("Jesse", "Liberty", 57),
    new Person("Jon", "Skeet", 38)
];

function getGroupedBy(persons, key) {
    var groups = {}, result = [];
    persons.forEach(function (a) {
        if (!(a[key] in groups)) {
            groups[a[key]] = [];
            result.push(groups[a[key]]);
        }
        groups[a[key]].push(a);
    });
    return result;
}

document.write('<pre>' + JSON.stringify(getGroupedBy(people, 'firstName'), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(getGroupedBy(people, 'lastName'), 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(getGroupedBy(people, 'age'), 0, 4) + '</pre>');
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392