0

I have an object which looks like the following

{
  "8 am": 2,
  "11 am": 6,
  "12 pm": 3,
  "5 pm": 7,
  "1 pm": 0
}

I am using the code below to sort the object using keys.

const ordered: any = {};
Object.keys(groupedData).sort().map((key) => {
     ordered[key] = groupedData[key];
});

I get a result as follows

 {
  "1 pm": 0,
  "8 am": 2,
  "11 am": 6,
  "12 pm": 3,
  "5 pm": 7,
}

However what I require is something like this

 {
  "8 am": 2,
  "11 am": 6,
  "12 pm": 3,
  "1 pm": 0,
  "5 pm": 7
}

How can I achieve this in typescript or javascript. Solutions with plugins are also welcome.

Tatenda
  • 587
  • 1
  • 5
  • 20
  • Does this answer your question? [Does JavaScript Guarantee Object Property Order?](https://stackoverflow.com/questions/5525795/does-javascript-guarantee-object-property-order) – AZ_ Jan 16 '20 at 10:13

2 Answers2

3

Make a function which can transform the string into its associated hour value (eg, 8 am -> 8, 3 pm -> 15), then .sort by that function:

const groupedData = {
  "8 am": 2,
  "11 am": 6,
  "12 pm": 3,
  "5 pm": 7,
  "1 pm": 0
}
const ordered = {};
const getVal = (str) => {
  if (str === '12 pm') {
    return 12;
  }
  const [num, ampm] = str.split(' ');
  return (ampm === 'pm') * 12 + Number(num);
};
Object.keys(groupedData).sort((a, b) => getVal(a) - getVal(b)).map((key) => {
  ordered[key] = groupedData[key];
});
console.log(ordered);

More elegantly, using Object.fromEntries:

const groupedData = {
  "8 am": 2,
  "11 am": 6,
  "12 pm": 3,
  "5 pm": 7,
  "1 pm": 0
}

const getVal = (str) => {
  if (str === '12 pm') {
    return 12;
  }
  const [num, ampm] = str.split(' ');
  return (ampm === 'pm') * 12 + Number(num);
};
const ordered = Object.fromEntries(
  Object.entries(groupedData).sort((a, b) => getVal(a[0]) - getVal(b[0]))
);
console.log(ordered);
CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • You cannot ensure the order of keys in and object. – AZ_ Jan 16 '20 at 10:12
  • Yes you can, see https://stackoverflow.com/a/58444013 All implementations follow it, and the specification will soon guarantee it too – CertainPerformance Jan 16 '20 at 10:13
  • @Tatenda Press "Run code snippet" - the keys *are* kept in 12 hour format. This does not change the keys, only their order. – CertainPerformance Jan 16 '20 at 10:15
  • @CertainPerformance (ampm === 'pm') * 12 + Number(num); is telling me that *The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type* in typescript.. any solution – Tatenda Jan 16 '20 at 10:32
  • @Tatenda You can cast to number explicitly for Typescript: `Number(ampm === 'pm')` – CertainPerformance Jan 16 '20 at 10:47
0

Make a custom function to sort the keys:

function sortHours(a, b) {
  const [aParsed, bParsed] = [a, b].map(x => {
    let [num, str] = x.split(' ');
    num = str === 'pm' ? num + 12 : num;
    return num;
  })
  return aParsed > bParsed ? 1 : -1;
}

And sort them:

Object.keys(a).sort(sortHours)

You should also leave sorted object as array, since Javascript doesn't retain order on object keys.

Roberto Zvjerković
  • 7,065
  • 2
  • 19
  • 35