1

I have a map of id => value that I want to sort by value. But no matter what I do, it always gets sorted by id.

Basically I have a sorted map on server side that I send to javascript via json.

{"3":"Apple","2":"Banana","1":"Orange"}

After de-serialization I get

{
    1:"Orange",
    2:"Banana",
    3:"Apple"
}

And no matter what I try, it seems to stay in this order. Is it possible in javascript to force a non ascending sort order with interger keys?

var json = '{"3":"Apple", "2":"Banana", "1":"Orange"}';

var data = $.parseJSON(json);

for (var ix in data) {
  console.log(ix + ": " + data[ix]);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Torge
  • 1,887
  • 1
  • 16
  • 28
  • 2
    Key order in javascript object is not guaranteed to be kept, you should **not** rely on it, though in the last specifications it should be more relyable. In any case, you may want to build an array instead, but you shouldn't rely on key order on a JSON parsed object or, really, on a generic javascript object. – briosheje Aug 06 '19 at 10:09

1 Answers1

2

You should not rely on objects key order for these reasons.

I personally would recommend you to either use a Map, or to build an Array instead.

Below is an example to build an array from your source: for simplicity, I've added a key property to make the sorting easier.

Note: I'm using Array.from to build the array, which is taking the length from the parsed object keys length, and using the callback to init the object inline.

var json = '{"3":"Apple", "2":"Banana", "1":"Orange"}';

// Parse the json string.
const parsed = JSON.parse(json);
// Acquire the keys length
const length = Object.keys(parsed).length;
// Build an array of objects ordered in the same way it came.
const result = Array.from({length}, (_, i) => ({key: length - i, [length - i]: parsed[length - i]}));
// Log a copy of the result.
console.log(JSON.parse(JSON.stringify(result)));
// Sort ascending:
result.sort((a,b) => a.key - b.key);
// Log a copy of the sorted result.
console.log(JSON.parse(JSON.stringify(result)));
// Sort descending:
result.sort((a,b) => b.key - a.key);
// log the sorted array
console.log(result);

If you really want to rely on key orders, you can (of course), but using an array is slightly cleverer and gives no chance to have something which is not ordered as expected, unless (of course) the sorting algorithm is wrong or fails for some reason (like if key is undefined or null or not numeric in the above case).

As a final note, I'm aware that the question is about sorting an object, but because of the above reasons, I think the correct answer is just to DON'T use an object at all in that scenario specifically.

briosheje
  • 6,538
  • 2
  • 31
  • 48
  • In addition, to have the result as a sorted array: `Object.values(data).sort();` – saulotoledo Aug 06 '19 at 10:28
  • I don't care if it is an object or array or map. As long as I can keep the ID as the key. Would be a bit of a pain, if I have to restructure the code to the example above. – Torge Aug 06 '19 at 11:33
  • @Torget just restructure the above to give the `ID` instead of the key, that's it. Otherwise, think about using the parsed json for key->value access and search and the array if you need to display / sort the data. The object approach is more efficient for direct lookup of keys, but it's not reliable for sorting, as mentioned. – briosheje Aug 06 '19 at 11:39
  • I just checked your link and it seems I really do not have an option beside going this way. *sigh* I used this already quite a lot. it is just the first time I need sorting and have integer keys instead of named keys. So lot's of places will be affected. But well... – Torge Aug 06 '19 at 11:40