47

How can I implement a

 ORDER BY sort1 DESC, sort2 DESC

logic in an JSON array like such:

    var items = '[
          {
            "sort1": 1,
            "sort2": 3,
            "name" : "a",
          },
          {
            "sort1": 1,
            "sort2": 2,
            "name" : "b",
          },
          {
            "sort1": 2,
            "sort2": 1,
            "name" : "c",
          }
    ]';

resulting in the new order :

b,a,c
4
  • 3
    Why are you putting your Array syntax inside (broken) string literal syntax? Commented Nov 3, 2012 at 17:39
  • I'm using JSON like this, is there a better way? Commented Nov 3, 2012 at 17:44
  • 1
    Since you're assigning the Array to the items variable, you're already in a JavaScript environment, so it doesn't make too much sense to first represent it as JSON markup, then parse it. If that was meant to represent JSON markup being sent from the server, then a better representation is to get rid of the extra var items = ...; syntax, and just show it as markup with a note explaining that it's your server side markup. Commented Nov 3, 2012 at 17:46
  • Possible duplicate of Sort by two values prioritizing on one of them Commented Aug 24, 2019 at 14:52

3 Answers 3

115

You should design your sorting function accordingly:

items.sort(function(a, b) {
  return a.sort1 - b.sort1  ||  a.sort2 - b.sort2;
});

(because || operator has lower precedence than - one, it's not necessary to use parenthesis here).

The logic is simple: if a.sort1 - b.sort1 expression evaluates to 0 (so these properties are equal), it will proceed with evaluating || expression - and return the result of a.sort2 - b.sort2.

As a sidenote, your items is actually a string literal, you have to JSON.parse to get an array:

const itemsStr = `[{
    "sort1": 1,
    "sort2": 3,
    "name": "a"
  },
  {
    "sort1": 1,
    "sort2": 2,
    "name": "b"
  },
  {
    "sort1": 2,
    "sort2": 1,
    "name": "c"
  }
]`;
const items = JSON.parse(itemsStr);
items.sort((a, b) => a.sort1 - b.sort1 || a.sort2 - b.sort2);
console.log(items);

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

8 Comments

using operator - might cause problem since the value might be strings.
I'm afraid you miss the point here, both in your comment and in your answer. Using - instead of < is the way to enforce comparing the operands as numbers, not as strings. Remember, '12' < '3' evaluates to true in JavaScript.
That’s exactly what I am saying. - only applies to numbers. I am not saying you are wrong. I am providing a general solution as I said in my answer.
‘12’ should be less than ‘3’.
Remember, explicit is better than implicit. If you want values to be compared as strings in any case, use String.localeCompare() instead. < is ambiguous; its result depends on operands types - and type juggling, if those are different.
|
9

You can avoid hardcoding by create a general function

function sortByMultipleKey(keys) {
    return function(a, b) {
        if (keys.length == 0) return 0; // force to equal if keys run out
        key = keys[0]; // take out the first key
        if (a[key] < b[key]) return -1; // will be 1 if DESC
        else if (a[key] > b[key]) return 1; // will be -1 if DESC
        else return sortByMultipleKey(keys.slice(1))(a, b);
    }
}

Running

items.sort(sortByMultipleKey(['sort1', 'sort2']));

will have you

[ { sort1: 1, sort2: 2, name: 'b' },
  { sort1: 1, sort2: 3, name: 'a' },
  { sort1: 2, sort2: 1, name: 'c' } ]

1 Comment

Sorry to say, but this implementation of generic function is way too inefficient. Not only using recursion here is dubious (you can just iterate over list of keys until comparison results in non-zero), for each 'comparison miss' there's a new instance of comparison function generated. Compare your code to lodash implementation, for example.
0

const itemsStr = `[{
    "sort1": 1,
    "sort2": 3,
    "name": "a"
  },
  {
    "sort1": 1,
    "sort2": 2,
    "name": "b"
  },
  {
    "sort1": 2,
    "sort2": 1,
    "name": "c"
  }
]`;
const items = JSON.parse(itemsStr);
items.sort((a, b) => a.sort1 - b.sort1 || a.sort2 - b.sort2);
console.log(items);

Comments

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.