supercoolville
supercoolville

Reputation: 9106

Sort data in objects/arrays on multiple keys

I have a multiplayer game and the gameplay data is stored like this:

var gameplays = [
    {id: "1", player1: "bob", player2: "tim", score1: 2, score2: 14},
    {id: "2", player1: "bob", player2: "tim", score1: 7, score2: 3},
    {id: "3", player1: "bob", player2: "tim", score1: 6, score2: 10},
    {id: "4", player1: "bob", player2: "tim", score1: 5, score2: 1}
];

What is the most efficient way to find the top 5 highscores from all the games by searching "score1" and "score2" and output them like this:

HIGHSCORES
1. Tim - 14
2. Tim - 10
3. Bob - 7
4. Bob - 6
5. Bob - 5

Upvotes: 0

Views: 80

Answers (4)

ChrisY
ChrisY

Reputation: 1783

If you'r going to benchmark this I would be interested in the performance of the "functional" kind of solution with Ramda.

var gameplays = [
    {id: "1", player1: "bob", player2: "tim", score1: 2, score2: 14},
    {id: "2", player1: "bob", player2: "tim", score1: 7, score2: 3},
    {id: "3", player1: "bob", player2: "tim", score1: 6, score2: 10},
    {id: "4", player1: "bob", player2: "tim", score1: 5, score2: 1}
];

// find the 5 top highscores regardless which player
const normalizeScore = ({id, player1, score1, player2, score2}) => 
    [{id, player1, score: score1}, {id, player2, score: score2}];
const sortByScore = (play1, play2) => play2.score - play1.score;

const normalizeGameplays = R.chain(normalizeScore); // chain === flatMap
const sortGameplays = R.sort(sortByScore);
const topFive = R.slice(0, 5);

const highscore = R.compose(topFive, sortGameplays, normalizeGameplays);

console.log(highscore(gameplays));

@See: https://jsbin.com/wixowu/edit?html,js,console

Upvotes: 0

elqueso101
elqueso101

Reputation: 84

const gameplays = [
    {id: "1", player1: "bob", player2: "tim", score1: 2, score2: 14},
    {id: "2", player1: "bob", player2: "tim", score1: 7, score2: 3},
    {id: "3", player1: "bob", player2: "tim", score1: 6, score2: 10},
    {id: "4", player1: "bob", player2: "tim", score1: 5, score2: 1}
];

First, write all relevant game information into an array of objects, each of which contain a player key corresponding to the player's name and a score key, which corresponds to the score:

const results = [];

gameplays.forEach(game => {
  for(let i = 1; i <= 2; i++) {
    results.push({});
    results[results.length - 1].player = `${game[`player${i}`].slice(0, 1).toUpperCase()}${game[`player${i}`].slice(1).toLowerCase()}`;
    results[results.length - 1].score = game[`score${i}`];
  }
});

Then, sort the array in descending order of scores before only keeping the top 5 with slice.

const topFive = results.sort((result1, result2) => result2.score - result1.score)
                       .slice(0, 5);

Finally, display the top 5 scores.

console.log('High Scores');

for(let i = 0; i < topFive.length; i++) {
  console.log(`${i + 1}. ${topFive[i].player} - ${topFive[i].score}`);
}

Upvotes: 1

Joe Lissner
Joe Lissner

Reputation: 2473

You can do it in a sort pretty easily I think with:

gameplays.sort(function(_a, _b){
    var a = _a.score1 > _a.score2 ? _a.score1 : _a.score2;
    var b = _b.score1 > _b.score2 ? _b.score1 : _b.score2;

    if(a < b) {
      return 1;
    }

    if(a > b) {
      return -1;
    }

    return 0;
})

Then, you you can access the top five with:

gameplays.slice(0, 5)

Upvotes: 0

gauravmuk
gauravmuk

Reputation: 1616

var scores = [];
for (var i = 0; i < gameplays.length; i++) {
    scores.push({score: gameplays[i].score1, name: gameplays[i].player1});
    scores.push({score: gameplays[i].score2, name: gameplays[i].player2});
}

scores.sort(function (a, b) {
    return b.score - a.score;
});

scores.splice(0, 5);

First, get the scores and flatten them in a scores array along with score and name of individual.

Then, we sort the array and splicing will get the top 5 scores with name.

Upvotes: 3

Related Questions