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
3 Answers 3
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);
-
using operator
-
might cause problem since the value might be strings.xhg– xhg2017年11月22日 00:28:46 +00:00Commented Nov 22, 2017 at 0:28 -
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 totrue
in JavaScript.raina77ow– raina77ow2017年11月22日 10:35:32 +00:00Commented Nov 22, 2017 at 10:35 -
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.xhg– xhg2017年11月22日 10:39:47 +00:00Commented Nov 22, 2017 at 10:39
-
1
-
4Remember, 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.raina77ow– raina77ow2017年11月22日 10:47:42 +00:00Commented Nov 22, 2017 at 10:47
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' } ]
-
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.raina77ow– raina77ow2017年11月22日 10:40:38 +00:00Commented Nov 22, 2017 at 10:40
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);
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 extravar items = ...;
syntax, and just show it as markup with a note explaining that it's your server side markup.