Reputation:
Suppose I have an object {'a':20,'b':6,'c':21,'d':12}
After getting sort by values in descending order,
The desired output : Keys: ['c','a','d','b']
and Values: [21,20,12,6]
How can I achieve that efficiently? I came to knew that we cannot we cant sort js object keys based on values, since the order of keys is random everytime.
Upvotes: 0
Views: 57
Reputation: 364
1) Get keys from an object
2) Sort keys based on val comparision
function cmp(a, b) {
return (a < b) ? 1 : (a > b) ? -1 : 0
}
function sortObj(obj) {
const keys = Object.keys(obj).sort((x,y) => cmp(obj[x],obj[y]))
const vals = keys.map(x => obj[x])
return {sortedKeys: keys, sortedValues: vals}
}
result = sortObj({'a':20,'b':6,'c':21,'d':12})
console.log(result)
Answer
{
sortedKeys: ["c", "a", "d", "b"]
sortedValues: [21, 20, 12, 6]
}
Upvotes: 0
Reputation: 1074465
I came to knew that we cannot we cant sort js object keys based on values, since the order of keys is random everytime.
That's not true (it's not random, and it's not different every time), but sorting JavaScript objects is almost never useful.
You have several options to get the array you've shown. One simple one is to use Object.entries
to get an array of [key, value]
arrays, then sort
that, then get just the keys from it via map
:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.map(([k, v]) => k);
console.log(keys);
Object.entries
is relatively new, but easily polyfilled if needed.
If you need it in ES5 (with Object.entries
polyfilled):
var obj = {'a':20,'b':6,'c':21,'d':12};
var keys = Object.entries(obj)
.sort(function(e1, e2) {
return e2[1] - e1[1];
})
.map(function(e) {
return e[0];
});
console.log(keys);
In a comment you've asked how to have the values in a separate array as well. You can either build that value array as a side-effect of map
by pushing into it, like this:
const obj = {'a':20,'b':6,'c':21,'d':12};
const values = [];
const keys = Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.map(([k, v]) => {
values.push(v);
return k;
});
console.log(keys);
console.log(values);
...or if using map
for side-effects bothers you (it's often not best practice), just use forEach
(or for-of
) instead:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = [];
const values = [];
Object.entries(obj)
.sort(([k1, v1], [k2, v2]) => v2 - v1)
.forEach(([k, v]) => {
keys.push(k);
values.push(v);
});
console.log(keys);
console.log(values);
The for-of
version:
const obj = {'a':20,'b':6,'c':21,'d':12};
const keys = [];
const values = [];
for (const [k, v] of Object.entries(obj).sort(([k1, v1], [k2, v2]) => v2 - v1)) {
keys.push(k);
values.push(v);
}
console.log(keys);
console.log(values);
(You might use a temporary variable for the result of .sort
, then use for (const [k, v] of theTemporaryVariable) {
.)
Upvotes: 3
Reputation: 1209
const obj = {'a':20,'b':6,'c':21,'d':12};
const result = Object.keys(obj)
.reduce((acc, key) => {
const value = obj[key];
acc.push({ key, value });
acc.sort((a, b) => b.value - a.value);
return acc;
}, []);
console.log(result);
output
[
{ key: 'c', value: 21 },
{ key: 'a', value: 20 }
{ key: 'd', value: 12 }
{ key: 'b', value: 6 }
]
Upvotes: 1
Reputation: 791
Try this.
const list = {'a':20,'b':6,'c':21,'d':12};
let myObject = Object.fromEntries(Object.entries(list).sort( (a,b) => b[1] - a[1] ));
Object.prototype.mySplit = function() {
return Object.keys(this).map((key) => {
return {
key: key,
value: this[key]
};
});
}
let keys = [];
let values = [];
let properties = myObject.mySplit();
for (var i = 0; i < properties.length; i++) {
keys.push(properties[i]['key']);
values.push(properties[i]['value']);
}
console.log(keys);
console.log(values);
Upvotes: 0