Home > Enterprise >  How do I sort a nested object by a property?
How do I sort a nested object by a property?

Time:09-14

I want to be able to sort the nested object below from the lowest number to the high number...

{
  "a": 50,
  "b": {
    "c": {
      "d": 69,
      "e": 420,
      "f": 21,
      "g": {
        "h": 5,
        "i": 3,
      }
    }
  },
  "j": 1,
  "k": 1000
}

... so that it can look like this:

{
  "j": 1, // min in OBJECT
  "b": {
    "c": { // min in B
      "g": { // min in C
        "i": 3, // min in G
        "h": 5
      },
      "f": 21,
      "d": 69,
      "e": 420
    }
  },
  "a": 50,
  "k": 1000
}

Note that the object is sorted by the lowest number inside objects, meaning the object's direct children's values are [1, 3, 50, 1000].

CodePudding user response:

Quick and dirty using Object.entries, Array forEach, Array reduce and Array sort

getpaths creates an array in the form

[
    ["a.b.c", 2],
    ["d.e", 1],
    ....
]

Which can then be sorted easily using Array sort

createPath takes a root object, a path and a value and creates the "path" in the object

so, given {}, "a.b.c", 2

would result in

{
  a: {
    b: {
      c: 2
    }
  }
}

Since (non numeric) object keys are "sorted" in insertion order, inserting the values in value order produces the object as required

let obj = { a: 50, b: { c: { d: 69, e: 420, f: 21, g: { h: 5, i: 3, }, }, }, j: 1, k: 1000 };

const getpaths = (obj) => {
    const paths = [];
    const fn = (obj, path = "") => {
        Object.entries(obj).forEach(([key, value]) => {
            if (typeof value === "object") {
                return fn(value, `${path}.${key}`);
            }
            paths.push([`${path}.${key}`.slice(1), value]);
        });
    };
    fn(obj);
    return paths;
};
const createPath = (obj, [path, value]) => {
    path.split(".").reduce(
        (acc, key, index, array) => acc[key] ||= array[index   1] ? {} : value, obj);
        
    return obj;
};

const result = getpaths(obj)
    .sort(([, a], [, b]) => a - b)
    .reduce((acc, item) => createPath(acc, item), {});
    
console.log(JSON.stringify(result, null, 4));

  • Related