1

I have an array of objects that represent hockey rank data:

[
  {
     name: "Russia",
     points: 10,
     iihf: 1
  },
  {
     name: "USA",
     points: 10,
     iihf: 7
  },
  {
     name: "Slovakia",
     points: 8,
     iihf: 6
  }
]

I want to sort the data descending from the highest score. If two or more teams share the same point count, they have to be fine sorted using next dimensions, namely the IIHF rank (ascending order). Is there an elegant solution to this?

Thanks.

5
  • 5
    What did you tried/searched? Commented Dec 30, 2013 at 11:59
  • 1
    I find this answer quite elegant ;] Commented Dec 30, 2013 at 12:00
  • 3
    @thg435 - possibly because it's your own? Commented Dec 30, 2013 at 12:02
  • 1
    possible duplicate of Javascript sort function. Sort by First then by Second Commented Dec 30, 2013 at 12:10
  • @DontVoteMeDown I've done a simple fn as sort param that sorted by dimension name, but couldn't wrap my head around how to keep the original sort intact while fine sorting the equals. Thought I had to extract the equals, sort those, and put them back into the original sort. Didn't know if I could do it in a less elaborate way, hence the question. Commented Dec 30, 2013 at 12:27

3 Answers 3

2

As addition: if you know an upper limit of the iihf score, you can also precompute a compound score, that you only use for sorting. The compound score could look like this:

obj.cscore = obj.points * 10000 + obj.iihf;

After that, you can just sort after the cscore:

arr.sort(function(a,b) { 
    return a.cscore - b.cscore;
});

If you don't want to pollute your original objects, you can use a temporary map (as described here):

var map = arr.map(function (e, i) {
    return {index: i, cscore: e.points * 1000 + e.iihf};
});

map.sort(function (a,b) {
    return a.cscore - b.cscore;
});

var result = map.map(function(e){
  return arr[e.index]
});

FIDDLE

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

5 Comments

return a.cscore < b.cscore ? 1 : -1 is not correct - you're missing the equal case. An elegant way to compare numbers is to return their difference: return a.score - b.score.
@thg435 thx, you're right. I actually mindlessly copied this part from the answer of adeneo (which also doesn't return zero). Anyway, I fixed it.
Great! Now the next step: since both sort fields are numbers, you can combine them using boolean or: return b.points - a.points || a.iihf - b.iihf - no need for a compound key.
@thg435 that's a really beautiful and simple way to solve this problem. Why didn't you post it as an answer? My goal was to introduce the general concept of a compound key. I realize that in this particular case, it might not be necessary but it is a way to solve the problem.
Yes, schwartzian transform is useful technique worth knowing about. Good job!
1

Use Array.sort(), if the values of points are equal, sort on iihf instead

arr.sort(function(a,b) {
    if (a.points == b.points) return a.iihf > b.iihf ? 1 : -1;    
    return a.points < b.points ? 1 : -1;
});

FIDDLE

Comments

0

Try this

function comparator(a, b) {
   if (a.points == b.points) return a.iihf > b.iihf ? 1 : -1;    
return a.points < b.points ? 1 : -1;
}

var json = { "homes": 
             [
  {
     name: "Russia",
     points: 10,
     iihf: 1
  },
  {
     name: "USA",
     points: 10,
     iihf: 7
  },
  {
     name: "Slovakia",
     points: 8,
     iihf: 6
  }
]};
console.log(json["homes"].sort(comparator));

DEMO

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.