3

I have an array of objects like this:

var a = [
    { id: 1, score: 1, isCut: false, dnf: false },
    { id: 2, score: 2, isCut: false, dnf: false },
    { id: 3, score: 3, isCut: false, dnf: false },
    { id: 4, score: 4, isCut: false, dnf: false },
    { id: 5, score: 5, isCut: true, dnf: true },
    { id: 6, score: 6, isCut: true, dnf: false },
    { id: 7, score: 7, isCut: true, dnf: false },
    { id: 8, score: 8, isCut: true, dnf: false },
    { id: 9, score: 9, isCut: true, dnf: false },
    { id: 10, score: 0, isCut: false, dnf: false },
    { id: 11, score: -1, isCut: false, dnf: false },
    { id: 12, score: -2, isCut: false, dnf: true },
    { id: 13, score: -3, isCut: false, dnf: false },
    { id: 14, score: -4, isCut: false, dnf: false },
    { id: 15, score: -5, isCut: false, dnf: false },
    { id: 16, score: 10, isCut: true, dnf: false }
];

I need to group and sort the array by the following criteria:

  1. if dnf is true, object goes to bottom; all dnf-objects should be sorted by score
  2. if isCut is true, object goes to bottom, but above dnfs; all isCut-objects should be sorted by score
  3. rest should be sorted by score, and if the scores are equal, by id
3
  • 5
    Array.sort accepts a comparator function. Commented Jul 30, 2013 at 9:28
  • 1
    Yes, but how to implement it, that is the question. Commented Jul 30, 2013 at 9:35
  • 2
    stackoverflow.com/questions/4576714/… look at this, I hope this will help you :) Commented Jul 30, 2013 at 10:00

3 Answers 3

12

(Updated) Here's the answer of question you mentioned in comment.

a.sort(function(a, b) {
  if (a.dnf != b.dnf) {
    return a.dnf ? 1 : -1;
  }
  if (!(a.dnf && b.dnf) && a.isCut != b.isCut) {
    return a.isCut ? 1 : -1;
  }
  if (a.score != b.score) {
    return b.score - a.score; // descending
  }
  return b.id - a.id; // descending
});

Result:

[
  {"id":4,"score":4,"isCut":false,"dnf":false},   // the rest: order by score, id
  {"id":3,"score":3,"isCut":false,"dnf":false},   //
  {"id":2,"score":2,"isCut":false,"dnf":false},   //
  {"id":1,"score":1,"isCut":false,"dnf":false},   //
  {"id":10,"score":0,"isCut":false,"dnf":false},  //
  {"id":11,"score":-1,"isCut":false,"dnf":false}, //
  {"id":13,"score":-3,"isCut":false,"dnf":false}, //
  {"id":14,"score":-4,"isCut":false,"dnf":false}, //
  {"id":15,"score":-5,"isCut":false,"dnf":false}, //
  {"id":16,"score":10,"isCut":true,"dnf":false}, // isCut: order by score, id
  {"id":9,"score":9,"isCut":true,"dnf":false},   //
  {"id":8,"score":8,"isCut":true,"dnf":false},   //
  {"id":7,"score":7,"isCut":true,"dnf":false},   //
  {"id":6,"score":6,"isCut":true,"dnf":false},   //
  {"id":5,"score":5,"isCut":true,"dnf":true},   // dnf: order by score, id
  {"id":12,"score":-2,"isCut":false,"dnf":true} //
]
Sign up to request clarification or add additional context in comments.

4 Comments

This is ordering by dnf first. isCut will not be ordered accurately. You first want all items where isCut is true followed by items where isCut is false.
@amberlamps I can't understand. Dosen't OP want to let dnf objects to bottom? Then we should order by dnf first.
You understood correctly, but he wants isCut above that if it is true. So it can look like true/true, true/false, false/true in that order.
You have to test it with lots of different data to be really sure, but I looks really fine so far. +1
0

This is a different approach, which uses an array for the sort order, which is irregular, if using dnf and isCut property without looking at both. If we take a both values to a truth table, then the sort order does not reflect the wanted order.

                   2*dnf+isCut
    dnf     isCut     value     order
--------  --------  --------  --------
     0         0         0         0
     0         1         1         1
     1         1         3         2
     1         0         2         3

To correct the sort order, I suggest to use an array for getting the right order.

var data = [{ id: 1, score: 1, isCut: false, dnf: false }, { id: 2, score: 2, isCut: false, dnf: false }, { id: 3, score: 3, isCut: false, dnf: false }, { id: 4, score: 4, isCut: false, dnf: false }, { id: 5, score: 5, isCut: true, dnf: true }, { id: 6, score: 6, isCut: true, dnf: false }, { id: 7, score: 7, isCut: true, dnf: false }, { id: 8, score: 8, isCut: true, dnf: false }, { id: 9, score: 9, isCut: true, dnf: false }, { id: 10, score: 0, isCut: false, dnf: false }, { id: 11, score: -1, isCut: false, dnf: false }, { id: 12, score: -2, isCut: false, dnf: true }, { id: 13, score: -3, isCut: false, dnf: false }, { id: 14, score: -4, isCut: false, dnf: false }, { id: 15, score: -5, isCut: false, dnf: false }, { id: 16, score: 10, isCut: true, dnf: false }];

data.sort(function (a, b) {
    function order(dnf, isCut) { return [0, 1, 3, 2][dnf * 2 + isCut]; }

    return order(a.dnf, a.isCut) - order(b.dnf, b.isCut) || b.score - a.score;
});

console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

-1

Use comparator function from Array

you can check answers here : Sort array of objects by string property value in JavaScript

1 Comment

This only works for strings. Author has multiple types to deal with.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.