0

I have this structure inside an array:

[
    {
        "playerName": "Stack",
        "leaguePoints": 100,
        "wins": 280,
        "miniSeries": {
            "progress": "WNN",
            "losses": 0,
            "wins": 1
        }
    },
    {
        "playerName": "Overflow",
        "leaguePoints": 90,
        "wins": 280
    }
    {
        "playerName": "StackOverflow",
        "leaguePoints": 0,
        "wins": 100
    }
]

I need to sort the array elements like this:

If leaguePoints = 100 then sort by (miniSeries.wins+miniSeries.losses (more games played, higher in rank)) or number of N(eutral) left in miniSeries.progress (less Ns left, higher in rank)

If leaguePoints < 100 then sort by leaguePoints

If leaguePoints = 0 then sort by wins

I've been using Ege Özcan's multiple parameters sort and it does sort by leaguePoints and wins, but I can't get it to work with the miniSeries.

How it should end up looking like:

Name    leaguePoints    Wins    MiniSeries
Stack   100             10      LWN
Stack   100             25      WNN
Stack   100             5       NNN
Stack   99              50      ---
Stack   70              250     ---
Stack   0               300     ---
Stack   0               200     ---
Stack   0               100     ---
Community
  • 1
  • 1
  • It's your custom sorter, you can make it return whatever you need – Yuriy Galanter Oct 14 '13 at 18:21
  • You mean sort by `leaguePoints`, iff equal *then* sort by wins or miniseries depending on points? What do you mean by wins+losses "or" progress, to sort by progress only if the others are equal? – Bergi Oct 14 '13 at 18:21
  • var gamesPlayed = miniSeries.wins + miniSeries.losses, sort based on gamesPlayed – Robert Manolea Oct 14 '13 at 18:24

2 Answers2

0

I think you better do a 2 pass processing.
First divide the data into 3 groups, leaguePoints100, leaguePoints0, and the rest.

You know how to sort each group separately, then use Array.concat() to merge the three sorted array, see sample here.

Lo-Dash can make the tasks easy, first groupBy() leaguePoints:

groups = _.groupBy(data, function(item) {
  switch (item.leaguePoints) {
    case 100:
        return 'leaguePoints100';
    case 0:
        return 'leaguePoints0';
    default:
        return 'other';
  }
);

Then sortBy() on the three groups:

groups['leaguePoints100'] = _.sortBy(group['leaguePoints100'], sortLeaguePoints100);
groups['leaguePoints0'] = _.sortBy(group['leaguePoints0'], 'wins');
groups['other'] = _.sortBy(group['other'], 'leaguePoints');

This make the code cleaner, but mechanical indeed.
KISS, dude.

Community
  • 1
  • 1
leesei
  • 6,020
  • 2
  • 29
  • 51
  • That was the first thing that came to mind, but it seems a little too mechanic. Thought there's a better way, a more optimized one. – Robert Manolea Oct 14 '13 at 18:31
0

I think you want

function byProgress(a, b) {
    // less "N"s in the value
    return b.split("N").length - a.split("N").length;
}
function byMiniSeries(a, b) {
    // more games played
    return a.wins+a.losses - b.wins-b.losses || byProgress(a.progress, b.progress);
}
function byRank(a, b) {
    // highest league
    return a.leaguePoints - b.leaguePoints || (a.leaguePoints == 0
      ? a.wins - b.wins
      : (a.leaguePoints == 100 
        ? byMiniSeries(a.miniSeries, b.miniSeries)
        : 0 ) );
}
playerArray.sort(byRank);

The || uses short-circuit evaluation, the right operand will be returned if the left one is falsy (here: 0, i.e. the values are equal).

Bergi
  • 630,263
  • 148
  • 957
  • 1,375