Search code examples
javascriptlodash

how to get top X via a filter, in an array of objects (Javascript)


requirement is to get the top X score(s) for EACH "user" in an array of objects.

the array of objects is already sorted by user, by score.

so for example if it's a "Top 3" we're after, and there are 4 rows in the array for user "barney" - then return the first 3 elements from the array for user "Barney".

another example: if it's "Top 3" we're after, and a user has 2 elements in the array - then return those 2 elements.

here's an example where i want the TOP 3:

var users = [
 { user: 'barney', score: 39},
 { user: 'barney', score: 37},
 { user: 'barney', score: 36},
 { user: 'barney', score: 36},
 { user: 'fred', score: 40},  
 { user: 'fred', score: 22},
 { user: 'wilma', score: 40},
 { user: 'wilma', score: 40}
];

so in this example the result should be:

[
 { user: 'barney', score: 39},
 { user: 'barney', score: 37},
 { user: 'barney', score: 36},
 { user: 'fred', score: 40},
 { user: 'fred', score: 22},
 { user: 'wilma', score: 40},
 { user: 'wilma', score: 40}
];

Solution

  • It is possible without lodash so it is also possible with lodash.

    Split the original array by user, use slice to keep the first x, merge everything back into 1 array.

    var users = [
     { user: 'barney', score: 39},
     { user: 'barney', score: 37},
     { user: 'barney', score: 36},
     { user: 'barney', score: 36},
     { user: 'fred', score: 40},  
     { user: 'fred', score: 22},
     { user: 'wilma', score: 40},
     { user: 'wilma', score: 40}
    ];
    var x = 3;
    
    var names = users.reduce((acc, n) => {
      acc.add(n.user);
      return acc;
    }, new Set());
    var groups = [...names].reduce((acc, n) => {
      acc.push(users.filter(m => m.user === n));
      return acc;
    }, []);
    groups = groups.map(n => n.slice(0, x));
    var result = groups.reduce((acc, n) => {
      acc.push(...n);
      return acc;
    }, []);
    console.log(result);