delux
delux

Reputation: 1886

How to sort object keys in an array, based on object properties?

I have an object with the following structure:

root_object: {
    ITEM_ONE: {
        order: 2,
        prop_one: '123',
        prop_two: '456',
    },
    ITEM_TWO: {
        order: 1,
        prop_one: '789',
        prop_two: '321',
    },
    ITEM_THREE: {
        order: 3,
        prop_one: '654',
        prop_two: '987',
    },
}

As an end result, I will need to get the list of keys:

['ITEM_ONE', 'ITEM_TWO', 'ITEM_THREE']

BUT they need to be ordered based on the property order, which will result as:

['ITEM_TWO', 'ITEM_ONE', 'ITEM_THREE']

I prefer to use the _lodash library for this purpose, but I'm not even sure how to start with it, since the structure for the root_object is an object and not a list.

Upvotes: 0

Views: 70

Answers (6)

Ori Drori
Ori Drori

Reputation: 191996

This is an O(n) solution (sort is O(nlogn)) that works only for unique order values.

You can use lodash to map the values of each property to the order ({ ITEM_ONE: 2, ITEM_TWO: 1, ... }), then invert the keys and values ({ 1: ITEM_TWO, 2: ITEM_ONE, ... }), and extract the values. This will get you the items in the right order:

const { flow, partialRight: pr, mapValues, invert, values } = _

const fn = flow(
  pr(mapValues, 'order'), // convert to { ITEM_ONE: 2, ITEM_TWO: 1, ... }
  invert, // convert to { 1: ITEM_TWO, 2: ITEM_ONE, ... }
  values // get the array of keys
)

const root_object = {"ITEM_ONE":{"order":2,"prop_one":"123","prop_two":"456"},"ITEM_TWO":{"order":1,"prop_one":"789","prop_two":"321"},"ITEM_THREE":{"order":3,"prop_one":"654","prop_two":"987"}}

const result = fn(root_object)
  
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

In vanilla JS by convert the object to entries, map the entries to the form of [order, key], convert the entries to object with Object.fromEntries() (not supported by IE/Edge), and then get the values:

const fn = o => Object.values(Object.fromEntries(
  Object.entries(o).map(([k, { order }]) => [order, k])
))

const root_object = {"ITEM_ONE":{"order":2,"prop_one":"123","prop_two":"456"},"ITEM_TWO":{"order":1,"prop_one":"789","prop_two":"321"},"ITEM_THREE":{"order":3,"prop_one":"654","prop_two":"987"}}

const result = fn(root_object)
  
console.log(result)

Upvotes: 1

Mark
Mark

Reputation: 1679

You can use Object.keys along with Array.map and Array.sort

const root_object = {
    ITEM_ONE: {
        order: 2,
        prop_one: '123',
        prop_two: '456',
    },
    ITEM_TWO: {
        order: 1,
        prop_one: '789',
        prop_two: '321',
    },
    ITEM_THREE: {
        order: 3,
        prop_one: '654',
        prop_two: '987',
    },
}

let rootArr = [];

let sortedRootObject = Object.keys(root_object).map(key => rootArr.push(root_object[key])).sort((a, b) => rootArr[b.order] - rootArr[a.order])

console.log(sortedRootObject)

Upvotes: 0

p.s.w.g
p.s.w.g

Reputation: 149030

Just use sort with a callback function, like so:

var root = {ITEM_ONE:{order:2,prop_one:'123',prop_two:'456'},ITEM_TWO:{order:1,prop_one:'789',prop_two:'321'},ITEM_THREE:{order:3,prop_one:'654',prop_two:'987'}};

var keys = Object.keys(root).sort((a, b) => root[a].order - root[b].order);
console.log(...keys);

For a lodash solution, use toPairs, sortBy, then map to get the keys:

var root = {ITEM_ONE:{order:2,prop_one:'123',prop_two:'456'},ITEM_TWO:{order:1,prop_one:'789',prop_two:'321'},ITEM_THREE:{order:3,prop_one:'654',prop_two:'987'}};

console.log(..._.map(_.sortBy(_.toPairs(root), '1.order'), 0));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Upvotes: 2

connexo
connexo

Reputation: 56753

Just use Array.prototype.sort() on the array of Object.keys(root_object):

const root_object = {
    ITEM_ONE: {
        order: 2,
        prop_one: '123',
        prop_two: '456',
    },
    ITEM_TWO: {
        order: 1,
        prop_one: '789',
        prop_two: '321',
    },
    ITEM_THREE: {
        order: 3,
        prop_one: '654',
        prop_two: '987',
    },
}

let result = Object.keys(root_object).sort((a,b) => root_object[a].order - root_object[b].order);

console.log(result);

Upvotes: 1

Nenad Vracar
Nenad Vracar

Reputation: 122057

You can do this with plain js using sort method and Object.keys.

const data = {"ITEM_ONE":{"order":2,"prop_one":"123","prop_two":"456"},"ITEM_TWO":{"order":1,"prop_one":"789","prop_two":"321"},"ITEM_THREE":{"order":3,"prop_one":"654","prop_two":"987"}}
const res = Object.keys(data).sort((a, b) => data[a].order - data[b].order)
console.log(res)

Upvotes: 4

Nina Scholz
Nina Scholz

Reputation: 386654

You could sort the keys by taking the value for sorting.

var object = { root_object: { ITEM_ONE: { order: 2, prop_one: '123', prop_two: '456' }, ITEM_TWO: { order: 1, prop_one: '789', prop_two: '321' }, ITEM_THREE: { order: 3, prop_one: '654', prop_two: '987' } } },
    keys = Object.keys(object.root_object);
    
keys.sort((a, b) => object.root_object[a].order - object.root_object[b].order);

console.log(keys);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 1

Related Questions