Search code examples
javascriptlodashtraversal

lodash groupBy is changing order in my collection


I have an array:

  { date: '25', value: '1410' },
  { date: '25', value: '1132' },
  { date: '26', value: '1482' },
  { date: '26', value: '3546' },
  { date: '27', value: '3748' },
  { date: '27', value: '3482' },
  { date: '28', value: '3164' },
  { date: '28', value: '2626' },
  { date: '29', value: '1110' },
  { date: '29', value: '948' },
  { date: '01', value: '1260' },
  { date: '01', value: '1228' },
  { date: '02', value: '1120' },
  { date: '02', value: '1056' },
  { date: '03', value: '1214' },
  { date: '04', value: '1100' },
  { date: '05', value: '1624' },
  { date: '06', value: '1544' },
  { date: '07', value: '1846' },
  { date: '08', value: '1370' },
  { date: '09', value: '1262' },
  { date: '10', value: '542' },
  { date: '10', value: '492' },

When I do:

 let groups = _.groupBy(conso, 'date');

I get the result grouped, but I lose the order, the first element is not 25, it is 10:

{
  '10': [
    { date: '10', value: '542' },
    { date: '10', value: '492' },
    ....
  ]
}

Is this the wanted behaviour ? If sorting alphabetically, shouldn't it begin with 01 ?

How should I do to keep the order of my collection ?


Solution

  • That is how properties are ordered in EcmaScript1: when the property name is the canonical string- representation of an array index value (i.e., decimal digits, up to 232-1, and without padded zeroes), then these are sorted in numerical order before any other properties.

    Note that this is not related to lodash, but to EcmaScript itself.

    To enforce an order you should not make your result a plain object, but an array with pairs, where the first value in the pair is the (numeric) property, and the second is the actual value (object array in your case).

    In plain JS you can create that pair-based structure with:

    let map = new Map(conso.map(o => [o.date, []]));
    conso.forEach(o => map.get(o.date).push(o));
    let result = [...map];
    

    If you really need the plain object format, then you could consider prefixing the properties with some non-digit character.


    1There are a lot of nuances to the "order" of object properties. See Does ES6 introduce a well-defined order of enumeration for object properties? for a more elaborate explanation