0

I can't sort a list of key/value pairs in an object in natural order when a leading zero precedes a 4-digit key.

This is the object with key/value pairs:

plain_options = { 
"1001":"Freizeile",
"1101":"Freizeile",
"1201":"Zwischenmahlzeit",
"1301":"Zwischenmahlzeit",
"0101":"Frühstück",
"0201":"Freizeile",
"0301":"Freizeile",
"0401":"Menü A",
"0501":"Menü B",
"0601":"Freizeile",
"0701":"Freizeile",
"0801":"Mittag 1",
"0901":"Mittag 2"
}

and i get this what is correct

sorted_options_parse_int = {
"0101":"Frühstück",
"0201":"Freizeile",
"0301":"Freizeile",
"0401":"Menü A",
"0501":"Menü B",
"0601":"Freizeile",
"0701":"Freizeile",
"0801":"Mittag 1",
"0901":"Mittag 2",
"1001":"Freizeile",
"1101":"Freizeile",
"1201":"Zwischenmahlzeit",
"1301":"Zwischenmahlzeit"
}

with following code:


function sortObjectByKeyParseInt(obj) {
    const sortedKeys = Object.keys(obj).sort((a, b) => parseInt(a, 10) - parseInt(b, 10));
     const sortedObj = {};
     sortedKeys.forEach(key => {
         sortedObj[key] = obj[key];
    });
    return sortedObj;
}

var sorted_options_parse_int = sortObjectByKeyParseInt(plain_options);
console.log('ParseInt: ', sorted_options_parse_int);

options = '';
Object.entries(sorted_options_parse_int).forEach((item) => {
 console.log('Item: ', item);
 options += '<option value="'+item[0]+'"><b>'+item[1]+'</b></option>';
});

but if loop over the object with forEach the sorting is different.

"Item: ", ["1001", "Freizeile"]
"Item: ", ["1101", "Freizeile"]
"Item: ", ["1201", "Zwischenmahlzeit"]
"Item: ", ["1301", "Zwischenmahlzeit"]
"Item: ", ["0101", "Frühstück"]
"Item: ", ["0201", "Freizeile"]
"Item: ", ["0301", "Freizeile"]
"Item: ", ["0401", "Menü A"]
"Item: ", ["0501", "Menü B"]
"Item: ", ["0601", "Freizeile"]
"Item: ", ["0701", "Freizeile"]
"Item: ", ["0801", "Mittag 1"]
"Item: ", ["0901", "Mittag 2"]
}

What is the problem why i get the 1001,1101,1201,1301 before the 0101,0201.... The keys are always numeric, with 4 digits and leading zeros. How can i resolve this?

I searched for a solution but find nothing, which point to this.

Many Thanks

EDIT:

I discovered that the problem is later in my code. I'm iterating over the generated object with forEach, it seems the sorting is interpreted differently in the forEach loop. Updated the Question and create a fiddle. Here is the fiddle: https://jsfiddle.net/gh5kt310/

Meatwant
  • 19
  • 1
  • 7
  • 1
    You can't have sorted keys in the object at all. You could instead have an array of sorted keys and loop over this sorted array if required. – nice_dev Jul 29 '23 at 05:30
  • 1
    Does this answer your question? [Is there a way to sort/order keys in JavaScript objects?](https://stackoverflow.com/questions/9658690/is-there-a-way-to-sort-order-keys-in-javascript-objects) – nice_dev Jul 29 '23 at 05:30
  • Sadly no, but found the Problem is later in the code, i updated the question to it. Thanks. – Meatwant Jul 29 '23 at 07:34
  • 1
    It is not really ordered. I have added 2 new keys to demonstrate. https://jsfiddle.net/wmkfaov1/ – nice_dev Jul 29 '23 at 08:09

2 Answers2

0

Keys are numeric strings. Therefore, they cannot be sorted correctly. If the keys are converted to numbers, the problem is solved as follows :

let plain_options = {
  "1001":"Freizeile",
  "1101":"Freizeile",
  "1201":"Zwischenmahlzeit",
  "1301":"Zwischenmahlzeit",
  "0101":"Frühstück",
  "0201":"Freizeile",
  "0301":"Freizeile",
  "0401":"Menü A",
  "0501":"Menü B",
  "0601":"Freizeile",
  "0701":"Freizeile",
  "0801":"Mittag 1",
  "0901":"Mittag 2"
}
function sortObjectByKeyParseInt(input) {
  const ordered = Object.keys(input).sort().reduce(
    (obj, key) => {
      obj[+key] = input[key];
      return obj;
    },
    {}
  );
  return ordered
}

const sorted_options_parse_int = sortObjectByKeyParseInt(plain_options);
console.log('ParseInt: ', sorted_options_parse_int);

output is :

{
  "101": "Frühstück",
  "201": "Freizeile",
  "301": "Freizeile",
  "401": "Menü A",
  "501": "Menü B",
  "601": "Freizeile",
  "701": "Freizeile",
  "801": "Mittag 1",
  "901": "Mittag 2",
  "1001": "Freizeile",
  "1101": "Freizeile",
  "1201": "Zwischenmahlzeit",
  "1301": "Zwischenmahlzeit"
}
-1

parseInt() removes the leading 0