Related
I need to sort JavaScript objects by key.
Hence the following:
{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
Would become:
{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
The other answers to this question are outdated, never matched implementation reality, and have officially become incorrect now that the ES6 / ES2015 spec has been published.
See the section on property iteration order in Exploring ES6 by Axel Rauschmayer:
All methods that iterate over property keys do so in the same order:
First all Array indices, sorted numerically.
Then all string keys (that are not indices), in the order in which they were created.
Then all symbols, in the order in which they were created.
So yes, JavaScript objects are in fact ordered, and the order of their keys/properties can be changed.
Here’s how you can sort an object by its keys/properties, alphabetically:
const unordered = {
'b': 'foo',
'c': 'bar',
'a': 'baz'
};
console.log(JSON.stringify(unordered));
// → '{"b":"foo","c":"bar","a":"baz"}'
const ordered = Object.keys(unordered).sort().reduce(
(obj, key) => {
obj[key] = unordered[key];
return obj;
},
{}
);
console.log(JSON.stringify(ordered));
// → '{"a":"baz","b":"foo","c":"bar"}'
Use var instead of const for compatibility with ES5 engines.
JavaScript objects1 are not ordered. It is meaningless to try to "sort" them. If you want to iterate over an object's properties, you can sort the keys and then retrieve the associated values:
var myObj = {
'b': 'asdsadfd',
'c': 'masdasaf',
'a': 'dsfdsfsdf'
},
keys = [],
k, i, len;
for (k in myObj) {
if (myObj.hasOwnProperty(k)) {
keys.push(k);
}
}
keys.sort();
len = keys.length;
for (i = 0; i < len; i++) {
k = keys[i];
console.log(k + ':' + myObj[k]);
}
Alternate implementation using Object.keys fanciness:
var myObj = {
'b': 'asdsadfd',
'c': 'masdasaf',
'a': 'dsfdsfsdf'
},
keys = Object.keys(myObj),
i, len = keys.length;
keys.sort();
for (i = 0; i < len; i++) {
k = keys[i];
console.log(k + ':' + myObj[k]);
}
1Not to be pedantic, but there's no such thing as a JSON object.
A lot of people have mention that "objects cannot be sorted", but after that they are giving you a solution which works. Paradox, isn't it?
No one mention why those solutions are working. They are, because in most of the browser's implementations values in objects are stored in the order in which they were added. That's why if you create new object from sorted list of keys it's returning an expected result.
And I think that we could add one more solution – ES5 functional way:
function sortObject(obj) {
return Object.keys(obj).sort().reduce(function (result, key) {
result[key] = obj[key];
return result;
}, {});
}
ES2015 version of above (formatted to "one-liner"):
const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})
Short explanation of above examples (as asked in comments):
Object.keys is giving us a list of keys in provided object (obj or o), then we're sorting those using default sorting algorithm, next .reduce is used to convert that array back into an object, but this time with all of the keys sorted.
Guys I'm figuratively shocked! Sure all answers are somewhat old, but no one did even mention the stability in sorting! So bear with me I'll try my best to answer the question itself and go into details here. So I'm going to apologize now it will be a lot to read.
Since it is 2018 I will only use ES6, the Polyfills are all available at the MDN docs, which I will link at the given part.
Answer to the question:
If your keys are only numbers then you can safely use Object.keys() together with Array.prototype.reduce() to return the sorted object:
// Only numbers to show it will be sorted.
const testObj = {
'2000': 'Articel1',
'4000': 'Articel2',
'1000': 'Articel3',
'3000': 'Articel4',
};
// I'll explain what reduces does after the answer.
console.log(Object.keys(testObj).reduce((accumulator, currentValue) => {
accumulator[currentValue] = testObj[currentValue];
return accumulator;
}, {}));
/**
* expected output:
* {
* '1000': 'Articel3',
* '2000': 'Articel1',
* '3000': 'Articel4',
* '4000': 'Articel2'
* }
*/
// if needed here is the one liner:
console.log(Object.keys(testObj).reduce((a, c) => (a[c] = testObj[c], a), {}));
However if you are working with strings I highly recommend chaining Array.prototype.sort() into all of this:
// String example
const testObj = {
'a1d78eg8fdg387fg38': 'Articel1',
'z12989dh89h31d9h39': 'Articel2',
'f1203391dhj32189h2': 'Articel3',
'b10939hd83f9032003': 'Articel4',
};
// Chained sort into all of this.
console.log(Object.keys(testObj).sort().reduce((accumulator, currentValue) => {
accumulator[currentValue] = testObj[currentValue];
return accumulator;
}, {}));
/**
* expected output:
* {
* a1d78eg8fdg387fg38: 'Articel1',
* b10939hd83f9032003: 'Articel4',
* f1203391dhj32189h2: 'Articel3',
* z12989dh89h31d9h39: 'Articel2'
* }
*/
// again the one liner:
console.log(Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}));
If someone is wondering what reduce does:
// Will return Keys of object as an array (sorted if only numbers or single strings like a,b,c).
Object.keys(testObj)
// Chaining reduce to the returned array from Object.keys().
// Array.prototype.reduce() takes one callback
// (and another param look at the last line) and passes 4 arguments to it:
// accumulator, currentValue, currentIndex and array
.reduce((accumulator, currentValue) => {
// setting the accumulator (sorted new object) with the actual property from old (unsorted) object.
accumulator[currentValue] = testObj[currentValue];
// returning the newly sorted object for the next element in array.
return accumulator;
// the empty object {} ist the initial value for Array.prototype.reduce().
}, {});
If needed here is the explanation for the one liner:
Object.keys(testObj).reduce(
// Arrow function as callback parameter.
(a, c) =>
// parenthesis return! so we can safe the return and write only (..., a);
(a[c] = testObj[c], a)
// initial value for reduce.
,{}
);
Docs for reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Why use parenthesis on JavaScript return statements: http://jamesknelson.com/javascript-return-parenthesis/
Why Sorting is a bit complicated:
In short Object.keys() will return an array with the same order as we get with a normal loop:
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]
Object.keys() returns an array whose elements are strings
corresponding to the enumerable properties found directly upon object.
The ordering of the properties is the same as that given by looping
over the properties of the object manually.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Sidenote - you can use Object.keys() on arrays as well, keep in mind the index will be returned:
// simple array
const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
But it is not as easy as shown by those examples, real world objects may contain numbers and alphabetical characters or even symbols (please don't do it).
Here is an example with all of them in one object:
// This is just to show what happens, please don't use symbols in keys.
const testObj = {
'1asc': '4444',
1000: 'a',
b: '1231',
'#01010101010': 'asd',
2: 'c'
};
console.log(Object.keys(testObj));
// output: [ '2', '1000', '1asc', 'b', '#01010101010' ]
Now if we use Array.prototype.sort() on the array above the output changes:
console.log(Object.keys(testObj).sort());
// output: [ '#01010101010', '1000', '1asc', '2', 'b' ]
Here is a quote from the docs:
The sort() method sorts the elements of an array in place and returns
the array. The sort is not necessarily stable. The default sort order
is according to string Unicode code points.
The time and space complexity of the sort cannot be guaranteed as it
is implementation dependent.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
You have to make sure that one of them returns the desired output for you. In reallife examples people tend to mix up things expecially if you use different information inputs like APIs and Databases together.
So what's the big deal?
Well there are two articles which every programmer should understand:
In-place algorithm:
In computer science, an in-place algorithm is an algorithm which transforms input using no auxiliary data structure. However a small amount of extra storage space is allowed for auxiliary variables. The input is usually overwritten by the output as the algorithm executes. In-place algorithm updates input sequence only through replacement or swapping of elements. An algorithm which is not in-place is sometimes called not-in-place or out-of-place.
So basically our old array will be overwritten! This is important if you want to keep the old array for other reasons. So keep this in mind.
Sorting algorithm
Stable sort algorithms sort identical elements in the same order that
they appear in the input. When sorting some kinds of data, only part
of the data is examined when determining the sort order. For example,
in the card sorting example to the right, the cards are being sorted
by their rank, and their suit is being ignored. This allows the
possibility of multiple different correctly sorted versions of the
original list. Stable sorting algorithms choose one of these,
according to the following rule: if two items compare as equal, like
the two 5 cards, then their relative order will be preserved, so that
if one came before the other in the input, it will also come before
the other in the output.
An example of stable sort on playing cards. When the cards are sorted
by rank with a stable sort, the two 5s must remain in the same order
in the sorted output that they were originally in. When they are
sorted with a non-stable sort, the 5s may end up in the opposite order
in the sorted output.
This shows that the sorting is right but it changed. So in the real world even if the sorting is correct we have to make sure that we get what we expect! This is super important keep this in mind as well. For more JavaScript examples look into the Array.prototype.sort() - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
It's 2019 and we have a 2019 way to solve this :)
Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())
ES6 - here is the 1 liner
var data = { zIndex:99,
name:'sravan',
age:25,
position:'architect',
amount:'100k',
manager:'mammu' };
console.log(Object.entries(data).sort().reduce( (o,[k,v]) => (o[k]=v,o), {} ));
This works for me
/**
* Return an Object sorted by it's Key
*/
var sortObjectByKey = function(obj){
var keys = [];
var sorted_obj = {};
for(var key in obj){
if(obj.hasOwnProperty(key)){
keys.push(key);
}
}
// sort keys
keys.sort();
// create new array based on Sorted Keys
jQuery.each(keys, function(i, key){
sorted_obj[key] = obj[key];
});
return sorted_obj;
};
This is an old question, but taking the cue from Mathias Bynens' answer, I've made a short version to sort the current object, without much overhead.
Object.keys(unordered).sort().forEach(function(key) {
var value = unordered[key];
delete unordered[key];
unordered[key] = value;
});
after the code execution, the "unordered" object itself will have the keys alphabetically sorted.
Using lodash this will work:
some_map = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
// perform a function in order of ascending key
_(some_map).keys().sort().each(function (key) {
var value = some_map[key];
// do something
});
// or alternatively to build a sorted list
sorted_list = _(some_map).keys().sort().map(function (key) {
var value = some_map[key];
// return something that shall become an item in the sorted list
}).value();
Just food for thought.
Suppose it could be useful in VisualStudio debugger which shows unordered object properties.
(function(s) {
var t = {};
Object.keys(s).sort().forEach(function(k) {
t[k] = s[k]
});
return t
})({
b: 2,
a: 1,
c: 3
});
The same as inline version:
(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})
I am actually very surprised that over 30 answers were given, and yet none gave a full deep solution for this problem. Some had shallow solution, while others had deep but faulty (it'll crash if undefined, function or symbol will be in the json).
Here is the full solution:
function sortObject(unordered, sortArrays = false) {
if (!unordered || typeof unordered !== 'object') {
return unordered;
}
if (Array.isArray(unordered)) {
const newArr = unordered.map((item) => sortObject(item, sortArrays));
if (sortArrays) {
newArr.sort();
}
return newArr;
}
const ordered = {};
Object.keys(unordered)
.sort()
.forEach((key) => {
ordered[key] = sortObject(unordered[key], sortArrays);
});
return ordered;
}
const json = {
b: 5,
a: [2, 1],
d: {
b: undefined,
a: null,
c: false,
d: true,
g: '1',
f: [],
h: {},
i: 1n,
j: () => {},
k: Symbol('a')
},
c: [
{
b: 1,
a: 1
}
]
};
console.log(sortObject(json, true));
Underscore version:
function order(unordered)
{
return _.object(_.sortBy(_.pairs(unordered),function(o){return o[0]}));
}
If you don't trust your browser for keeping the order of the keys, I strongly suggest to rely on a ordered array of key-value paired arrays.
_.sortBy(_.pairs(c),function(o){return o[0]})
function sortObjectKeys(obj){
return Object.keys(obj).sort().reduce((acc,key)=>{
acc[key]=obj[key];
return acc;
},{});
}
sortObjectKeys({
telephone: '069911234124',
name: 'Lola',
access: true,
});
Maybe a bit more elegant form:
/**
* Sorts a key-value object by key, maintaining key to data correlations.
* #param {Object} src key-value object
* #returns {Object}
*/
var ksort = function ( src ) {
var keys = Object.keys( src ),
target = {};
keys.sort();
keys.forEach(function ( key ) {
target[ key ] = src[ key ];
});
return target;
};
// Usage
console.log(ksort({
a:1,
c:3,
b:2
}));
P.S. and the same with ES6+ syntax:
function ksort( src ) {
const keys = Object.keys( src );
keys.sort();
return keys.reduce(( target, key ) => {
target[ key ] = src[ key ];
return target;
}, {});
};
Here is a one line solution (not the most efficient but when it comes to thin objects like in your example I'd rather use native JS functions then messing up with sloppy loops)
const unordered = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
const ordered = Object.fromEntries(Object.entries(unordered).sort())
console.log(ordered); // a->b->c
// if keys are char/string
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( ));
let obj = { c: 3, a: 1 };
obj = sortObject(obj)
// if keys are numbers
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( (a,b)=>a-b ));
let obj = { 3: 'c', 1: 'a' };
obj = sortObject(obj)
const sortObjectByKeys = (object, asc = true) => Object.fromEntries(
Object.entries(object).sort(([k1], [k2]) => k1 < k2 ^ !asc ? -1 : 1),
)
const object = { b: 'asdsad', c: 'masdas', a: 'dsfdsfsdf' }
const orderedObject = sortObjectByKeys(object)
console.log(orderedObject)
recursive sort, for nested object and arrays
function sortObjectKeys(obj){
return Object.keys(obj).sort().reduce((acc,key)=>{
if (Array.isArray(obj[key])){
acc[key]=obj[key].map(sortObjectKeys);
}
if (typeof obj[key] === 'object'){
acc[key]=sortObjectKeys(obj[key]);
}
else{
acc[key]=obj[key];
}
return acc;
},{});
}
// test it
sortObjectKeys({
telephone: '069911234124',
name: 'Lola',
access: true,
cars: [
{name: 'Family', brand: 'Volvo', cc:1600},
{
name: 'City', brand: 'VW', cc:1200,
interior: {
wheel: 'plastic',
radio: 'blaupunkt'
}
},
{
cc:2600, name: 'Killer', brand: 'Plymouth',
interior: {
wheel: 'wooden',
radio: 'earache!'
}
},
]
});
Here is a clean lodash-based version that works with nested objects
/**
* Sort of the keys of an object alphabetically
*/
const sortKeys = function(obj) {
if(_.isArray(obj)) {
return obj.map(sortKeys);
}
if(_.isObject(obj)) {
return _.fromPairs(_.keys(obj).sort().map(key => [key, sortKeys(obj[key])]));
}
return obj;
};
It would be even cleaner if lodash had a toObject() method...
There's a great project by #sindresorhus called sort-keys that works awesome.
You can check its source code here:
https://github.com/sindresorhus/sort-keys
Or you can use it with npm:
$ npm install --save sort-keys
Here are also code examples from his readme
const sortKeys = require('sort-keys');
sortKeys({c: 0, a: 0, b: 0});
//=> {a: 0, b: 0, c: 0}
sortKeys({b: {b: 0, a: 0}, a: 0}, {deep: true});
//=> {a: 0, b: {a: 0, b: 0}}
sortKeys({c: 0, a: 0, b: 0}, {
compare: (a, b) => -a.localeCompare(b)
});
//=> {c: 0, b: 0, a: 0}
Object.keys(unordered).sort().reduce(
(acc,curr) => ({...acc, [curr]:unordered[curr]})
, {}
)
Use this code if you have nested objects or if you have nested array obj.
var sortObjectByKey = function(obj){
var keys = [];
var sorted_obj = {};
for(var key in obj){
if(obj.hasOwnProperty(key)){
keys.push(key);
}
}
// sort keys
keys.sort();
// create new array based on Sorted Keys
jQuery.each(keys, function(i, key){
var val = obj[key];
if(val instanceof Array){
//do for loop;
var arr = [];
jQuery.each(val,function(){
arr.push(sortObjectByKey(this));
});
val = arr;
}else if(val instanceof Object){
val = sortObjectByKey(val)
}
sorted_obj[key] = val;
});
return sorted_obj;
};
As already mentioned, objects are unordered.
However...
You may find this idiom useful:
var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
var kv = [];
for (var k in o) {
kv.push([k, o[k]]);
}
kv.sort()
You can then iterate through kv and do whatever you wish.
> kv.sort()
[ [ 'a', 'dsfdsfsdf' ],
[ 'b', 'asdsad' ],
[ 'c', 'masdas' ] ]
Just use lodash to unzip map and sortBy first value of pair and zip again it will return sorted key.
If you want sortby value change pair index to 1 instead of 0
var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
console.log(_(o).toPairs().sortBy(0).fromPairs().value())
Sorts keys recursively while preserving references.
function sortKeys(o){
if(o && o.constructor === Array)
o.forEach(i=>sortKeys(i));
else if(o && o.constructor === Object)
Object.entries(o).sort((a,b)=>a[0]>b[0]?1:-1).forEach(e=>{
sortKeys(e[1]);
delete o[e[0]];
o[e[0]] = e[1];
});
}
Example:
let x = {d:3, c:{g:20, a:[3,2,{s:200, a:100}]}, a:1};
let y = x.c;
let z = x.c.a[2];
sortKeys(x);
console.log(x); // {a: 1, c: {a: [3, 2, {a: 1, s: 2}], g: 2}, d: 3}
console.log(y); // {a: [3, 2, {a: 100, s: 200}}, g: 20}
console.log(z); // {a: 100, s: 200}
This is a lightweight solution to everything I need for JSON sorting.
function sortObj(obj) {
if (typeof obj !== "object" || obj === null)
return obj;
if (Array.isArray(obj))
return obj.map((e) => sortObj(e)).sort();
return Object.keys(obj).sort().reduce((sorted, k) => {
sorted[k] = sortObj(obj[k]);
return sorted;
}, {});
}
Solution:
function getSortedObject(object) {
var sortedObject = {};
var keys = Object.keys(object);
keys.sort();
for (var i = 0, size = keys.length; i < size; i++) {
key = keys[i];
value = object[key];
sortedObject[key] = value;
}
return sortedObject;
}
// Test run
getSortedObject({d: 4, a: 1, b: 2, c: 3});
Explanation:
Many JavaScript runtimes store values inside an object in the order in which they are added.
To sort the properties of an object by their keys you can make use of the Object.keys function which will return an array of keys. The array of keys can then be sorted by the Array.prototype.sort() method which sorts the elements of an array in place (no need to assign them to a new variable).
Once the keys are sorted you can start using them one-by-one to access the contents of the old object to fill a new object (which is now sorted).
Below is an example of the procedure (you can test it in your targeted browsers):
/**
* Returns a copy of an object, which is ordered by the keys of the original object.
*
* #param {Object} object - The original object.
* #returns {Object} Copy of the original object sorted by keys.
*/
function getSortedObject(object) {
// New object which will be returned with sorted keys
var sortedObject = {};
// Get array of keys from the old/current object
var keys = Object.keys(object);
// Sort keys (in place)
keys.sort();
// Use sorted keys to copy values from old object to the new one
for (var i = 0, size = keys.length; i < size; i++) {
key = keys[i];
value = object[key];
sortedObject[key] = value;
}
// Return the new object
return sortedObject;
}
/**
* Test run
*/
var unsortedObject = {
d: 4,
a: 1,
b: 2,
c: 3
};
var sortedObject = getSortedObject(unsortedObject);
for (var key in sortedObject) {
var text = "Key: " + key + ", Value: " + sortedObject[key];
var paragraph = document.createElement('p');
paragraph.textContent = text;
document.body.appendChild(paragraph);
}
Note: Object.keys is an ECMAScript 5.1 method but here is a polyfill for older browsers:
if (!Object.keys) {
Object.keys = function (object) {
var key = [];
var property = undefined;
for (property in object) {
if (Object.prototype.hasOwnProperty.call(object, property)) {
key.push(property);
}
}
return key;
};
}
I transfered some Java enums to javascript objects.
These objects returned correct arrays for me. if object keys are mixed type (string, int, char), there is a problem.
var Helper = {
isEmpty: function (obj) {
return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
},
isObject: function (obj) {
return (typeof obj === 'object');
},
sortObjectKeys: function (object) {
return Object.keys(object)
.sort(function (a, b) {
c = a - b;
return c
});
},
containsItem: function (arr, item) {
if (arr && Array.isArray(arr)) {
return arr.indexOf(item) > -1;
} else {
return arr === item;
}
},
pushArray: function (arr1, arr2) {
if (arr1 && arr2 && Array.isArray(arr1)) {
arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
}
}
};
function TypeHelper() {
var _types = arguments[0],
_defTypeIndex = 0,
_currentType,
_value;
if (arguments.length == 2) {
_defTypeIndex = arguments[1];
}
Object.defineProperties(this, {
Key: {
get: function () {
return _currentType;
},
set: function (val) {
_currentType.setType(val, true);
},
enumerable: true
},
Value: {
get: function () {
return _types[_currentType];
},
set: function (val) {
_value.setType(val, false);
},
enumerable: true
}
});
this.getAsList = function (keys) {
var list = [];
Helper.sortObjectKeys(_types).forEach(function (key, idx, array) {
if (key && _types[key]) {
if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) {
var json = {};
json.Key = key;
json.Value = _types[key];
Helper.pushArray(list, json);
}
}
});
return list;
};
this.setType = function (value, isKey) {
if (!Helper.isEmpty(value)) {
Object.keys(_types).forEach(function (key, idx, array) {
if (Helper.isObject(value)) {
if (value && value.Key == key) {
_currentType = key;
}
} else if (isKey) {
if (value && value.toString() == key.toString()) {
_currentType = key;
}
} else if (value && value.toString() == _types[key]) {
_currentType = key;
}
});
} else {
this.setDefaultType();
}
return isKey ? _types[_currentType] : _currentType;
};
this.setTypeByIndex = function (index) {
var keys = Helper.sortObjectKeys(_types);
for (var i = 0; i < keys.length; i++) {
if (index === i) {
_currentType = keys[index];
break;
}
}
};
this.setDefaultType = function () {
this.setTypeByIndex(_defTypeIndex);
};
this.setDefaultType();
}
var TypeA = {
"-1": "Any",
"2": "2L",
"100": "100L",
"200": "200L",
"1000": "1000L"
};
var TypeB = {
"U": "Any",
"W": "1L",
"V": "2L",
"A": "100L",
"Z": "200L",
"K": "1000L"
};
console.log('keys of TypeA', Helper.sortObjectKeys(TypeA));//keys of TypeA ["-1", "2", "100", "200", "1000"]
console.log('keys of TypeB', Helper.sortObjectKeys(TypeB));//keys of TypeB ["U", "W", "V", "A", "Z", "K"]
var objectTypeA = new TypeHelper(TypeA),
objectTypeB = new TypeHelper(TypeB);
console.log('list of objectA = ', objectTypeA.getAsList());
console.log('list of objectB = ', objectTypeB.getAsList());
Types:
var TypeA = {
"-1": "Any",
"2": "2L",
"100": "100L",
"200": "200L",
"1000": "1000L"
};
var TypeB = {
"U": "Any",
"W": "1L",
"V": "2L",
"A": "100L",
"Z": "200L",
"K": "1000L"
};
Sorted Keys(output):
Key list of TypeA -> ["-1", "2", "100", "200", "1000"]
Key list of TypeB -> ["U", "W", "V", "A", "Z", "K"]
The one line:
Object.entries(unordered)
.sort(([keyA], [keyB]) => keyA > keyB)
.reduce((obj, [key,value]) => Object.assign(obj, {[key]: value}), {})
Pure JavaScript answer to sort an Object. This is the only answer that I know of that will handle negative numbers. This function is for sorting numerical Objects.
Input
obj = {1000: {}, -1200: {}, 10000: {}, 200: {}};
function osort(obj) {
var keys = Object.keys(obj);
var len = keys.length;
var rObj = [];
var rK = [];
var t = Object.keys(obj).length;
while(t > rK.length) {
var l = null;
for(var x in keys) {
if(l && parseInt(keys[x]) < parseInt(l)) {
l = keys[x];
k = x;
}
if(!l) { // Find Lowest
var l = keys[x];
var k = x;
}
}
delete keys[k];
rK.push(l);
}
for (var i = 0; i < len; i++) {
k = rK[i];
rObj.push(obj[k]);
}
return rObj;
}
The output will be an object sorted by those numbers with new keys starting at 0.
I need to sort JavaScript objects by key.
Hence the following:
{ 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
Would become:
{ 'a' : 'dsfdsfsdf', 'b' : 'asdsad', 'c' : 'masdas' }
The other answers to this question are outdated, never matched implementation reality, and have officially become incorrect now that the ES6 / ES2015 spec has been published.
See the section on property iteration order in Exploring ES6 by Axel Rauschmayer:
All methods that iterate over property keys do so in the same order:
First all Array indices, sorted numerically.
Then all string keys (that are not indices), in the order in which they were created.
Then all symbols, in the order in which they were created.
So yes, JavaScript objects are in fact ordered, and the order of their keys/properties can be changed.
Here’s how you can sort an object by its keys/properties, alphabetically:
const unordered = {
'b': 'foo',
'c': 'bar',
'a': 'baz'
};
console.log(JSON.stringify(unordered));
// → '{"b":"foo","c":"bar","a":"baz"}'
const ordered = Object.keys(unordered).sort().reduce(
(obj, key) => {
obj[key] = unordered[key];
return obj;
},
{}
);
console.log(JSON.stringify(ordered));
// → '{"a":"baz","b":"foo","c":"bar"}'
Use var instead of const for compatibility with ES5 engines.
JavaScript objects1 are not ordered. It is meaningless to try to "sort" them. If you want to iterate over an object's properties, you can sort the keys and then retrieve the associated values:
var myObj = {
'b': 'asdsadfd',
'c': 'masdasaf',
'a': 'dsfdsfsdf'
},
keys = [],
k, i, len;
for (k in myObj) {
if (myObj.hasOwnProperty(k)) {
keys.push(k);
}
}
keys.sort();
len = keys.length;
for (i = 0; i < len; i++) {
k = keys[i];
console.log(k + ':' + myObj[k]);
}
Alternate implementation using Object.keys fanciness:
var myObj = {
'b': 'asdsadfd',
'c': 'masdasaf',
'a': 'dsfdsfsdf'
},
keys = Object.keys(myObj),
i, len = keys.length;
keys.sort();
for (i = 0; i < len; i++) {
k = keys[i];
console.log(k + ':' + myObj[k]);
}
1Not to be pedantic, but there's no such thing as a JSON object.
A lot of people have mention that "objects cannot be sorted", but after that they are giving you a solution which works. Paradox, isn't it?
No one mention why those solutions are working. They are, because in most of the browser's implementations values in objects are stored in the order in which they were added. That's why if you create new object from sorted list of keys it's returning an expected result.
And I think that we could add one more solution – ES5 functional way:
function sortObject(obj) {
return Object.keys(obj).sort().reduce(function (result, key) {
result[key] = obj[key];
return result;
}, {});
}
ES2015 version of above (formatted to "one-liner"):
const sortObject = o => Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {})
Short explanation of above examples (as asked in comments):
Object.keys is giving us a list of keys in provided object (obj or o), then we're sorting those using default sorting algorithm, next .reduce is used to convert that array back into an object, but this time with all of the keys sorted.
Guys I'm figuratively shocked! Sure all answers are somewhat old, but no one did even mention the stability in sorting! So bear with me I'll try my best to answer the question itself and go into details here. So I'm going to apologize now it will be a lot to read.
Since it is 2018 I will only use ES6, the Polyfills are all available at the MDN docs, which I will link at the given part.
Answer to the question:
If your keys are only numbers then you can safely use Object.keys() together with Array.prototype.reduce() to return the sorted object:
// Only numbers to show it will be sorted.
const testObj = {
'2000': 'Articel1',
'4000': 'Articel2',
'1000': 'Articel3',
'3000': 'Articel4',
};
// I'll explain what reduces does after the answer.
console.log(Object.keys(testObj).reduce((accumulator, currentValue) => {
accumulator[currentValue] = testObj[currentValue];
return accumulator;
}, {}));
/**
* expected output:
* {
* '1000': 'Articel3',
* '2000': 'Articel1',
* '3000': 'Articel4',
* '4000': 'Articel2'
* }
*/
// if needed here is the one liner:
console.log(Object.keys(testObj).reduce((a, c) => (a[c] = testObj[c], a), {}));
However if you are working with strings I highly recommend chaining Array.prototype.sort() into all of this:
// String example
const testObj = {
'a1d78eg8fdg387fg38': 'Articel1',
'z12989dh89h31d9h39': 'Articel2',
'f1203391dhj32189h2': 'Articel3',
'b10939hd83f9032003': 'Articel4',
};
// Chained sort into all of this.
console.log(Object.keys(testObj).sort().reduce((accumulator, currentValue) => {
accumulator[currentValue] = testObj[currentValue];
return accumulator;
}, {}));
/**
* expected output:
* {
* a1d78eg8fdg387fg38: 'Articel1',
* b10939hd83f9032003: 'Articel4',
* f1203391dhj32189h2: 'Articel3',
* z12989dh89h31d9h39: 'Articel2'
* }
*/
// again the one liner:
console.log(Object.keys(testObj).sort().reduce((a, c) => (a[c] = testObj[c], a), {}));
If someone is wondering what reduce does:
// Will return Keys of object as an array (sorted if only numbers or single strings like a,b,c).
Object.keys(testObj)
// Chaining reduce to the returned array from Object.keys().
// Array.prototype.reduce() takes one callback
// (and another param look at the last line) and passes 4 arguments to it:
// accumulator, currentValue, currentIndex and array
.reduce((accumulator, currentValue) => {
// setting the accumulator (sorted new object) with the actual property from old (unsorted) object.
accumulator[currentValue] = testObj[currentValue];
// returning the newly sorted object for the next element in array.
return accumulator;
// the empty object {} ist the initial value for Array.prototype.reduce().
}, {});
If needed here is the explanation for the one liner:
Object.keys(testObj).reduce(
// Arrow function as callback parameter.
(a, c) =>
// parenthesis return! so we can safe the return and write only (..., a);
(a[c] = testObj[c], a)
// initial value for reduce.
,{}
);
Docs for reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce
Why use parenthesis on JavaScript return statements: http://jamesknelson.com/javascript-return-parenthesis/
Why Sorting is a bit complicated:
In short Object.keys() will return an array with the same order as we get with a normal loop:
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]
Object.keys() returns an array whose elements are strings
corresponding to the enumerable properties found directly upon object.
The ordering of the properties is the same as that given by looping
over the properties of the object manually.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Sidenote - you can use Object.keys() on arrays as well, keep in mind the index will be returned:
// simple array
const arr = ['a', 'b', 'c'];
console.log(Object.keys(arr)); // console: ['0', '1', '2']
But it is not as easy as shown by those examples, real world objects may contain numbers and alphabetical characters or even symbols (please don't do it).
Here is an example with all of them in one object:
// This is just to show what happens, please don't use symbols in keys.
const testObj = {
'1asc': '4444',
1000: 'a',
b: '1231',
'#01010101010': 'asd',
2: 'c'
};
console.log(Object.keys(testObj));
// output: [ '2', '1000', '1asc', 'b', '#01010101010' ]
Now if we use Array.prototype.sort() on the array above the output changes:
console.log(Object.keys(testObj).sort());
// output: [ '#01010101010', '1000', '1asc', '2', 'b' ]
Here is a quote from the docs:
The sort() method sorts the elements of an array in place and returns
the array. The sort is not necessarily stable. The default sort order
is according to string Unicode code points.
The time and space complexity of the sort cannot be guaranteed as it
is implementation dependent.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
You have to make sure that one of them returns the desired output for you. In reallife examples people tend to mix up things expecially if you use different information inputs like APIs and Databases together.
So what's the big deal?
Well there are two articles which every programmer should understand:
In-place algorithm:
In computer science, an in-place algorithm is an algorithm which transforms input using no auxiliary data structure. However a small amount of extra storage space is allowed for auxiliary variables. The input is usually overwritten by the output as the algorithm executes. In-place algorithm updates input sequence only through replacement or swapping of elements. An algorithm which is not in-place is sometimes called not-in-place or out-of-place.
So basically our old array will be overwritten! This is important if you want to keep the old array for other reasons. So keep this in mind.
Sorting algorithm
Stable sort algorithms sort identical elements in the same order that
they appear in the input. When sorting some kinds of data, only part
of the data is examined when determining the sort order. For example,
in the card sorting example to the right, the cards are being sorted
by their rank, and their suit is being ignored. This allows the
possibility of multiple different correctly sorted versions of the
original list. Stable sorting algorithms choose one of these,
according to the following rule: if two items compare as equal, like
the two 5 cards, then their relative order will be preserved, so that
if one came before the other in the input, it will also come before
the other in the output.
An example of stable sort on playing cards. When the cards are sorted
by rank with a stable sort, the two 5s must remain in the same order
in the sorted output that they were originally in. When they are
sorted with a non-stable sort, the 5s may end up in the opposite order
in the sorted output.
This shows that the sorting is right but it changed. So in the real world even if the sorting is correct we have to make sure that we get what we expect! This is super important keep this in mind as well. For more JavaScript examples look into the Array.prototype.sort() - docs: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
It's 2019 and we have a 2019 way to solve this :)
Object.fromEntries(Object.entries({b: 3, a:8, c:1}).sort())
ES6 - here is the 1 liner
var data = { zIndex:99,
name:'sravan',
age:25,
position:'architect',
amount:'100k',
manager:'mammu' };
console.log(Object.entries(data).sort().reduce( (o,[k,v]) => (o[k]=v,o), {} ));
This works for me
/**
* Return an Object sorted by it's Key
*/
var sortObjectByKey = function(obj){
var keys = [];
var sorted_obj = {};
for(var key in obj){
if(obj.hasOwnProperty(key)){
keys.push(key);
}
}
// sort keys
keys.sort();
// create new array based on Sorted Keys
jQuery.each(keys, function(i, key){
sorted_obj[key] = obj[key];
});
return sorted_obj;
};
This is an old question, but taking the cue from Mathias Bynens' answer, I've made a short version to sort the current object, without much overhead.
Object.keys(unordered).sort().forEach(function(key) {
var value = unordered[key];
delete unordered[key];
unordered[key] = value;
});
after the code execution, the "unordered" object itself will have the keys alphabetically sorted.
Using lodash this will work:
some_map = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
// perform a function in order of ascending key
_(some_map).keys().sort().each(function (key) {
var value = some_map[key];
// do something
});
// or alternatively to build a sorted list
sorted_list = _(some_map).keys().sort().map(function (key) {
var value = some_map[key];
// return something that shall become an item in the sorted list
}).value();
Just food for thought.
Suppose it could be useful in VisualStudio debugger which shows unordered object properties.
(function(s) {
var t = {};
Object.keys(s).sort().forEach(function(k) {
t[k] = s[k]
});
return t
})({
b: 2,
a: 1,
c: 3
});
The same as inline version:
(function(s){var t={};Object.keys(s).sort().forEach(function(k){t[k]=s[k]});return t})({b:2,a:1,c:3})
I am actually very surprised that over 30 answers were given, and yet none gave a full deep solution for this problem. Some had shallow solution, while others had deep but faulty (it'll crash if undefined, function or symbol will be in the json).
Here is the full solution:
function sortObject(unordered, sortArrays = false) {
if (!unordered || typeof unordered !== 'object') {
return unordered;
}
if (Array.isArray(unordered)) {
const newArr = unordered.map((item) => sortObject(item, sortArrays));
if (sortArrays) {
newArr.sort();
}
return newArr;
}
const ordered = {};
Object.keys(unordered)
.sort()
.forEach((key) => {
ordered[key] = sortObject(unordered[key], sortArrays);
});
return ordered;
}
const json = {
b: 5,
a: [2, 1],
d: {
b: undefined,
a: null,
c: false,
d: true,
g: '1',
f: [],
h: {},
i: 1n,
j: () => {},
k: Symbol('a')
},
c: [
{
b: 1,
a: 1
}
]
};
console.log(sortObject(json, true));
Underscore version:
function order(unordered)
{
return _.object(_.sortBy(_.pairs(unordered),function(o){return o[0]}));
}
If you don't trust your browser for keeping the order of the keys, I strongly suggest to rely on a ordered array of key-value paired arrays.
_.sortBy(_.pairs(c),function(o){return o[0]})
function sortObjectKeys(obj){
return Object.keys(obj).sort().reduce((acc,key)=>{
acc[key]=obj[key];
return acc;
},{});
}
sortObjectKeys({
telephone: '069911234124',
name: 'Lola',
access: true,
});
Maybe a bit more elegant form:
/**
* Sorts a key-value object by key, maintaining key to data correlations.
* #param {Object} src key-value object
* #returns {Object}
*/
var ksort = function ( src ) {
var keys = Object.keys( src ),
target = {};
keys.sort();
keys.forEach(function ( key ) {
target[ key ] = src[ key ];
});
return target;
};
// Usage
console.log(ksort({
a:1,
c:3,
b:2
}));
P.S. and the same with ES6+ syntax:
function ksort( src ) {
const keys = Object.keys( src );
keys.sort();
return keys.reduce(( target, key ) => {
target[ key ] = src[ key ];
return target;
}, {});
};
Here is a one line solution (not the most efficient but when it comes to thin objects like in your example I'd rather use native JS functions then messing up with sloppy loops)
const unordered = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' }
const ordered = Object.fromEntries(Object.entries(unordered).sort())
console.log(ordered); // a->b->c
// if keys are char/string
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( ));
let obj = { c: 3, a: 1 };
obj = sortObject(obj)
// if keys are numbers
const sortObject = (obj) => Object.fromEntries(Object.entries(obj).sort( (a,b)=>a-b ));
let obj = { 3: 'c', 1: 'a' };
obj = sortObject(obj)
const sortObjectByKeys = (object, asc = true) => Object.fromEntries(
Object.entries(object).sort(([k1], [k2]) => k1 < k2 ^ !asc ? -1 : 1),
)
const object = { b: 'asdsad', c: 'masdas', a: 'dsfdsfsdf' }
const orderedObject = sortObjectByKeys(object)
console.log(orderedObject)
recursive sort, for nested object and arrays
function sortObjectKeys(obj){
return Object.keys(obj).sort().reduce((acc,key)=>{
if (Array.isArray(obj[key])){
acc[key]=obj[key].map(sortObjectKeys);
}
if (typeof obj[key] === 'object'){
acc[key]=sortObjectKeys(obj[key]);
}
else{
acc[key]=obj[key];
}
return acc;
},{});
}
// test it
sortObjectKeys({
telephone: '069911234124',
name: 'Lola',
access: true,
cars: [
{name: 'Family', brand: 'Volvo', cc:1600},
{
name: 'City', brand: 'VW', cc:1200,
interior: {
wheel: 'plastic',
radio: 'blaupunkt'
}
},
{
cc:2600, name: 'Killer', brand: 'Plymouth',
interior: {
wheel: 'wooden',
radio: 'earache!'
}
},
]
});
Here is a clean lodash-based version that works with nested objects
/**
* Sort of the keys of an object alphabetically
*/
const sortKeys = function(obj) {
if(_.isArray(obj)) {
return obj.map(sortKeys);
}
if(_.isObject(obj)) {
return _.fromPairs(_.keys(obj).sort().map(key => [key, sortKeys(obj[key])]));
}
return obj;
};
It would be even cleaner if lodash had a toObject() method...
There's a great project by #sindresorhus called sort-keys that works awesome.
You can check its source code here:
https://github.com/sindresorhus/sort-keys
Or you can use it with npm:
$ npm install --save sort-keys
Here are also code examples from his readme
const sortKeys = require('sort-keys');
sortKeys({c: 0, a: 0, b: 0});
//=> {a: 0, b: 0, c: 0}
sortKeys({b: {b: 0, a: 0}, a: 0}, {deep: true});
//=> {a: 0, b: {a: 0, b: 0}}
sortKeys({c: 0, a: 0, b: 0}, {
compare: (a, b) => -a.localeCompare(b)
});
//=> {c: 0, b: 0, a: 0}
Object.keys(unordered).sort().reduce(
(acc,curr) => ({...acc, [curr]:unordered[curr]})
, {}
)
Use this code if you have nested objects or if you have nested array obj.
var sortObjectByKey = function(obj){
var keys = [];
var sorted_obj = {};
for(var key in obj){
if(obj.hasOwnProperty(key)){
keys.push(key);
}
}
// sort keys
keys.sort();
// create new array based on Sorted Keys
jQuery.each(keys, function(i, key){
var val = obj[key];
if(val instanceof Array){
//do for loop;
var arr = [];
jQuery.each(val,function(){
arr.push(sortObjectByKey(this));
});
val = arr;
}else if(val instanceof Object){
val = sortObjectByKey(val)
}
sorted_obj[key] = val;
});
return sorted_obj;
};
As already mentioned, objects are unordered.
However...
You may find this idiom useful:
var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
var kv = [];
for (var k in o) {
kv.push([k, o[k]]);
}
kv.sort()
You can then iterate through kv and do whatever you wish.
> kv.sort()
[ [ 'a', 'dsfdsfsdf' ],
[ 'b', 'asdsad' ],
[ 'c', 'masdas' ] ]
Just use lodash to unzip map and sortBy first value of pair and zip again it will return sorted key.
If you want sortby value change pair index to 1 instead of 0
var o = { 'b' : 'asdsad', 'c' : 'masdas', 'a' : 'dsfdsfsdf' };
console.log(_(o).toPairs().sortBy(0).fromPairs().value())
Sorts keys recursively while preserving references.
function sortKeys(o){
if(o && o.constructor === Array)
o.forEach(i=>sortKeys(i));
else if(o && o.constructor === Object)
Object.entries(o).sort((a,b)=>a[0]>b[0]?1:-1).forEach(e=>{
sortKeys(e[1]);
delete o[e[0]];
o[e[0]] = e[1];
});
}
Example:
let x = {d:3, c:{g:20, a:[3,2,{s:200, a:100}]}, a:1};
let y = x.c;
let z = x.c.a[2];
sortKeys(x);
console.log(x); // {a: 1, c: {a: [3, 2, {a: 1, s: 2}], g: 2}, d: 3}
console.log(y); // {a: [3, 2, {a: 100, s: 200}}, g: 20}
console.log(z); // {a: 100, s: 200}
This is a lightweight solution to everything I need for JSON sorting.
function sortObj(obj) {
if (typeof obj !== "object" || obj === null)
return obj;
if (Array.isArray(obj))
return obj.map((e) => sortObj(e)).sort();
return Object.keys(obj).sort().reduce((sorted, k) => {
sorted[k] = sortObj(obj[k]);
return sorted;
}, {});
}
Solution:
function getSortedObject(object) {
var sortedObject = {};
var keys = Object.keys(object);
keys.sort();
for (var i = 0, size = keys.length; i < size; i++) {
key = keys[i];
value = object[key];
sortedObject[key] = value;
}
return sortedObject;
}
// Test run
getSortedObject({d: 4, a: 1, b: 2, c: 3});
Explanation:
Many JavaScript runtimes store values inside an object in the order in which they are added.
To sort the properties of an object by their keys you can make use of the Object.keys function which will return an array of keys. The array of keys can then be sorted by the Array.prototype.sort() method which sorts the elements of an array in place (no need to assign them to a new variable).
Once the keys are sorted you can start using them one-by-one to access the contents of the old object to fill a new object (which is now sorted).
Below is an example of the procedure (you can test it in your targeted browsers):
/**
* Returns a copy of an object, which is ordered by the keys of the original object.
*
* #param {Object} object - The original object.
* #returns {Object} Copy of the original object sorted by keys.
*/
function getSortedObject(object) {
// New object which will be returned with sorted keys
var sortedObject = {};
// Get array of keys from the old/current object
var keys = Object.keys(object);
// Sort keys (in place)
keys.sort();
// Use sorted keys to copy values from old object to the new one
for (var i = 0, size = keys.length; i < size; i++) {
key = keys[i];
value = object[key];
sortedObject[key] = value;
}
// Return the new object
return sortedObject;
}
/**
* Test run
*/
var unsortedObject = {
d: 4,
a: 1,
b: 2,
c: 3
};
var sortedObject = getSortedObject(unsortedObject);
for (var key in sortedObject) {
var text = "Key: " + key + ", Value: " + sortedObject[key];
var paragraph = document.createElement('p');
paragraph.textContent = text;
document.body.appendChild(paragraph);
}
Note: Object.keys is an ECMAScript 5.1 method but here is a polyfill for older browsers:
if (!Object.keys) {
Object.keys = function (object) {
var key = [];
var property = undefined;
for (property in object) {
if (Object.prototype.hasOwnProperty.call(object, property)) {
key.push(property);
}
}
return key;
};
}
I transfered some Java enums to javascript objects.
These objects returned correct arrays for me. if object keys are mixed type (string, int, char), there is a problem.
var Helper = {
isEmpty: function (obj) {
return !obj || obj === null || obj === undefined || Array.isArray(obj) && obj.length === 0;
},
isObject: function (obj) {
return (typeof obj === 'object');
},
sortObjectKeys: function (object) {
return Object.keys(object)
.sort(function (a, b) {
c = a - b;
return c
});
},
containsItem: function (arr, item) {
if (arr && Array.isArray(arr)) {
return arr.indexOf(item) > -1;
} else {
return arr === item;
}
},
pushArray: function (arr1, arr2) {
if (arr1 && arr2 && Array.isArray(arr1)) {
arr1.push.apply(arr1, Array.isArray(arr2) ? arr2 : [arr2]);
}
}
};
function TypeHelper() {
var _types = arguments[0],
_defTypeIndex = 0,
_currentType,
_value;
if (arguments.length == 2) {
_defTypeIndex = arguments[1];
}
Object.defineProperties(this, {
Key: {
get: function () {
return _currentType;
},
set: function (val) {
_currentType.setType(val, true);
},
enumerable: true
},
Value: {
get: function () {
return _types[_currentType];
},
set: function (val) {
_value.setType(val, false);
},
enumerable: true
}
});
this.getAsList = function (keys) {
var list = [];
Helper.sortObjectKeys(_types).forEach(function (key, idx, array) {
if (key && _types[key]) {
if (!Helper.isEmpty(keys) && Helper.containsItem(keys, key) || Helper.isEmpty(keys)) {
var json = {};
json.Key = key;
json.Value = _types[key];
Helper.pushArray(list, json);
}
}
});
return list;
};
this.setType = function (value, isKey) {
if (!Helper.isEmpty(value)) {
Object.keys(_types).forEach(function (key, idx, array) {
if (Helper.isObject(value)) {
if (value && value.Key == key) {
_currentType = key;
}
} else if (isKey) {
if (value && value.toString() == key.toString()) {
_currentType = key;
}
} else if (value && value.toString() == _types[key]) {
_currentType = key;
}
});
} else {
this.setDefaultType();
}
return isKey ? _types[_currentType] : _currentType;
};
this.setTypeByIndex = function (index) {
var keys = Helper.sortObjectKeys(_types);
for (var i = 0; i < keys.length; i++) {
if (index === i) {
_currentType = keys[index];
break;
}
}
};
this.setDefaultType = function () {
this.setTypeByIndex(_defTypeIndex);
};
this.setDefaultType();
}
var TypeA = {
"-1": "Any",
"2": "2L",
"100": "100L",
"200": "200L",
"1000": "1000L"
};
var TypeB = {
"U": "Any",
"W": "1L",
"V": "2L",
"A": "100L",
"Z": "200L",
"K": "1000L"
};
console.log('keys of TypeA', Helper.sortObjectKeys(TypeA));//keys of TypeA ["-1", "2", "100", "200", "1000"]
console.log('keys of TypeB', Helper.sortObjectKeys(TypeB));//keys of TypeB ["U", "W", "V", "A", "Z", "K"]
var objectTypeA = new TypeHelper(TypeA),
objectTypeB = new TypeHelper(TypeB);
console.log('list of objectA = ', objectTypeA.getAsList());
console.log('list of objectB = ', objectTypeB.getAsList());
Types:
var TypeA = {
"-1": "Any",
"2": "2L",
"100": "100L",
"200": "200L",
"1000": "1000L"
};
var TypeB = {
"U": "Any",
"W": "1L",
"V": "2L",
"A": "100L",
"Z": "200L",
"K": "1000L"
};
Sorted Keys(output):
Key list of TypeA -> ["-1", "2", "100", "200", "1000"]
Key list of TypeB -> ["U", "W", "V", "A", "Z", "K"]
The one line:
Object.entries(unordered)
.sort(([keyA], [keyB]) => keyA > keyB)
.reduce((obj, [key,value]) => Object.assign(obj, {[key]: value}), {})
Pure JavaScript answer to sort an Object. This is the only answer that I know of that will handle negative numbers. This function is for sorting numerical Objects.
Input
obj = {1000: {}, -1200: {}, 10000: {}, 200: {}};
function osort(obj) {
var keys = Object.keys(obj);
var len = keys.length;
var rObj = [];
var rK = [];
var t = Object.keys(obj).length;
while(t > rK.length) {
var l = null;
for(var x in keys) {
if(l && parseInt(keys[x]) < parseInt(l)) {
l = keys[x];
k = x;
}
if(!l) { // Find Lowest
var l = keys[x];
var k = x;
}
}
delete keys[k];
rK.push(l);
}
for (var i = 0; i < len; i++) {
k = rK[i];
rObj.push(obj[k]);
}
return rObj;
}
The output will be an object sorted by those numbers with new keys starting at 0.
I'd like to sum the values of an object.
I'm used to python where it would just be:
sample = { 'a': 1 , 'b': 2 , 'c':3 };
summed = sum(sample.itervalues())
The following code works, but it's a lot of code:
function obj_values(object) {
var results = [];
for (var property in object)
results.push(object[property]);
return results;
}
function list_sum( list ){
return list.reduce(function(previousValue, currentValue, index, array){
return previousValue + currentValue;
});
}
function object_values_sum( obj ){
return list_sum(obj_values(obj));
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = list_sum(obj_values(a));
var summed = object_values_sum(a)
Am i missing anything obvious, or is this just the way it is?
It can be as simple as that:
const sumValues = obj => Object.values(obj).reduce((a, b) => a + b, 0);
Quoting MDN:
The Object.values() method returns an array of a given object's own enumerable property values, in the same order as that provided by a for...in loop (the difference being that a for-in loop enumerates properties in the prototype chain as well).
from Object.values() on MDN
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
from Array.prototype.reduce() on MDN
You can use this function like that:
sumValues({a: 4, b: 6, c: -5, d: 0}); // gives 5
Note that this code uses some ECMAScript features which are not supported by some older browsers (like IE). You might need to use Babel to compile your code.
You could put it all in one function:
function sum( obj ) {
var sum = 0;
for( var el in obj ) {
if( obj.hasOwnProperty( el ) ) {
sum += parseFloat( obj[el] );
}
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
var summed = sum( sample );
console.log( "sum: "+summed );
For fun's sake here is another implementation using Object.keys() and Array.reduce() (browser support should not be a big issue anymore):
function sum(obj) {
return Object.keys(obj).reduce((sum,key)=>sum+parseFloat(obj[key]||0),0);
}
let sample = { a: 1 , b: 2 , c:3 };
console.log(`sum:${sum(sample)}`);
But this seems to be way slower: jsperf.com
If you're using lodash you can do something like
_.sum(_.values({ 'a': 1 , 'b': 2 , 'c':3 }))
Now you can make use of reduce function and get the sum.
const object1 = { 'a': 1 , 'b': 2 , 'c':3 }
console.log(Object.values(object1).reduce((a, b) => a + b, 0));
A regular for loop is pretty concise:
var total = 0;
for (var property in object) {
total += object[property];
}
You might have to add in object.hasOwnProperty if you modified the prototype.
Honestly, given our "modern times" I'd go with a functional programming approach whenever possible, like so:
const sumValues = (obj) => Object.keys(obj).reduce((acc, value) => acc + obj[value], 0);
Our accumulator acc, starting with a value of 0, is accumulating all looped values of our object. This has the added benefit of not depending on any internal or external variables; it's a constant function so it won't be accidentally overwritten... win for ES2015!
Any reason you're not just using a simple for...in loop?
var sample = { a: 1 , b: 2 , c:3 };
var summed = 0;
for (var key in sample) {
summed += sample[key];
};
http://jsfiddle.net/vZhXs/
let prices = {
"apple": 100,
"banana": 300,
"orange": 250
};
let sum = 0;
for (let price of Object.values(prices)) {
sum += price;
}
alert(sum)
I am a bit tardy to the party, however, if you require a more robust and flexible solution then here is my contribution. If you want to sum only a specific property in a nested object/array combo, as well as perform other aggregate methods, then here is a little function I have been using on a React project:
var aggregateProperty = function(obj, property, aggregate, shallow, depth) {
//return aggregated value of a specific property within an object (or array of objects..)
if ((typeof obj !== 'object' && typeof obj !== 'array') || !property) {
return;
}
obj = JSON.parse(JSON.stringify(obj)); //an ugly way of copying the data object instead of pointing to its reference (so the original data remains unaffected)
const validAggregates = [ 'sum', 'min', 'max', 'count' ];
aggregate = (validAggregates.indexOf(aggregate.toLowerCase()) !== -1 ? aggregate.toLowerCase() : 'sum'); //default to sum
//default to false (if true, only searches (n) levels deep ignoring deeply nested data)
if (shallow === true) {
shallow = 2;
} else if (isNaN(shallow) || shallow < 2) {
shallow = false;
}
if (isNaN(depth)) {
depth = 1; //how far down the rabbit hole have we travelled?
}
var value = ((aggregate == 'min' || aggregate == 'max') ? null : 0);
for (var prop in obj) {
if (!obj.hasOwnProperty(prop)) {
continue;
}
var propValue = obj[prop];
var nested = (typeof propValue === 'object' || typeof propValue === 'array');
if (nested) {
//the property is an object or an array
if (prop == property && aggregate == 'count') {
value++;
}
if (shallow === false || depth < shallow) {
propValue = aggregateProperty(propValue, property, aggregate, shallow, depth+1); //recursively aggregate nested objects and arrays
} else {
continue; //skip this property
}
}
//aggregate the properties value based on the selected aggregation method
if ((prop == property || nested) && propValue) {
switch(aggregate) {
case 'sum':
if (!isNaN(propValue)) {
value += propValue;
}
break;
case 'min':
if ((propValue < value) || !value) {
value = propValue;
}
break;
case 'max':
if ((propValue > value) || !value) {
value = propValue;
}
break;
case 'count':
if (propValue) {
if (nested) {
value += propValue;
} else {
value++;
}
}
break;
}
}
}
return value;
}
It is recursive, non ES6, and it should work in most semi-modern browsers. You use it like this:
const onlineCount = aggregateProperty(this.props.contacts, 'online', 'count');
Parameter breakdown:
obj = either an object or an array
property = the property within the nested objects/arrays you wish to perform the aggregate method on
aggregate = the aggregate method (sum, min, max, or count)
shallow = can either be set to true/false or a numeric value
depth = should be left null or undefined (it is used to track the subsequent recursive callbacks)
Shallow can be used to enhance performance if you know that you will not need to search deeply nested data. For instance if you had the following array:
[
{
id: 1,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 2,
otherData: { ... },
valueToBeTotaled: ?
},
{
id: 3,
otherData: { ... },
valueToBeTotaled: ?
},
...
]
If you wanted to avoid looping through the otherData property since the value you are going to be aggregating is not nested that deeply, you could set shallow to true.
Use Lodash
import _ from 'Lodash';
var object_array = [{a: 1, b: 2, c: 3}, {a: 4, b: 5, c: 6}];
return _.sumBy(object_array, 'c')
// return => 9
I came across this solution from #jbabey while trying to solve a similar problem. With a little modification, I got it right. In my case, the object keys are numbers (489) and strings ("489"). Hence to solve this, each key is parse. The following code works:
var array = {"nR": 22, "nH": 7, "totB": "2761", "nSR": 16, "htRb": "91981"}
var parskey = 0;
for (var key in array) {
parskey = parseInt(array[key]);
sum += parskey;
};
return(sum);
A ramda one liner:
import {
compose,
sum,
values,
} from 'ramda'
export const sumValues = compose(sum, values);
Use:
const summed = sumValues({ 'a': 1 , 'b': 2 , 'c':3 });
We can iterate object using in keyword and can perform any arithmetic operation.
// input
const sample = {
'a': 1,
'b': 2,
'c': 3
};
// var
let sum = 0;
// object iteration
for (key in sample) {
//sum
sum += (+sample[key]);
}
// result
console.log("sum:=>", sum);
A simple solution would be to use the for..in loop to find the sum.
function findSum(obj){
let sum = 0;
for(property in obj){
sum += obj[property];
}
return sum;
}
var sample = { a: 1 , b: 2 , c:3 };
console.log(findSum(sample));
function myFunction(a) { return Object.values(a).reduce((sum, cur) => sum + cur, 0); }
Sum the object key value by parse Integer. Converting string format to integer and summing the values
var obj = {
pay: 22
};
obj.pay;
console.log(obj.pay);
var x = parseInt(obj.pay);
console.log(x + 20);
function totalAmountAdjectives(obj) {
let sum = 0;
for(let el in obj) {
sum += el.length;
}
return sum;
}
console.log(totalAmountAdjectives({ a: "apple" }))
A simple and clean solution for typescrip:
const sample = { a: 1, b: 2, c: 3 };
const totalSample = Object.values(sample).reduce(
(total: number, currentElement: number) => total + currentElement
);
console.log(totalSample);
Good luck!
I need to find arrays where all values are equal. What's the fastest way to do this? Should I loop through it and just compare values?
['a', 'a', 'a', 'a'] // true
['a', 'a', 'b', 'a'] // false
const allEqual = arr => arr.every( v => v === arr[0] )
allEqual( [1,1,1,1] ) // true
Or one-liner:
[1,1,1,1].every( (val, i, arr) => val === arr[0] ) // true
Array.prototype.every (from MDN) :
The every() method tests whether all elements in the array pass the test implemented by the provided function.
Edit: Be a Red ninja:
!!array.reduce(function(a, b){ return (a === b) ? a : NaN; });
Results:
var array = ["a", "a", "a"] => result: "true"
var array = ["a", "b", "a"] => result: "false"
var array = ["false", ""] => result: "false"
var array = ["false", false] => result: "false"
var array = ["false", "false"] => result: "true"
var array = [NaN, NaN] => result: "false"
Warning:
var array = [] => result: TypeError thrown
This is because we do not pass an initialValue. So, you may wish to check array.length first.
You can turn the Array into a Set. If the size of the Set is equal to 1, then all elements of the Array are equal.
function allEqual(arr) {
return new Set(arr).size == 1;
}
allEqual(['a', 'a', 'a', 'a']); // true
allEqual(['a', 'a', 'b', 'a']); // false
This works. You create a method on Array by using prototype.
if (Array.prototype.allValuesSame === undefined) {
Array.prototype.allValuesSame = function() {
for (let i = 1; i < this.length; i++) {
if (this[i] !== this[0]) {
return false;
}
}
return true;
}
}
Call this in this way:
let a = ['a', 'a', 'a'];
let b = a.allValuesSame(); // true
a = ['a', 'b', 'a'];
b = a.allValuesSame(); // false
In JavaScript 1.6, you can use Array.every:
function AllTheSame(array) {
var first = array[0];
return array.every(function(element) {
return element === first;
});
}
You probably need some sanity checks, e.g. when the array has no elements. (Also, this won't work when all elements are NaN since NaN !== NaN, but that shouldn't be an issue... right?)
And for performance comparison I also did a benchmark:
function allAreEqual(array){
if(!array.length) return true;
// I also made sure it works with [false, false] array
return array.reduce(function(a, b){return (a === b)?a:(!b);}) === array[0];
}
function same(a) {
if (!a.length) return true;
return !a.filter(function (e) {
return e !== a[0];
}).length;
}
function allTheSame(array) {
var first = array[0];
return array.every(function(element) {
return element === first;
});
}
function useSome(array){
return !array.some(function(value, index, array){
return value !== array[0];
});
}
Results:
allAreEqual x 47,565 ops/sec ±0.16% (100 runs sampled)
same x 42,529 ops/sec ±1.74% (92 runs sampled)
allTheSame x 66,437 ops/sec ±0.45% (102 runs sampled)
useSome x 70,102 ops/sec ±0.27% (100 runs sampled)
So apparently using builtin array.some() is the fastest method of the ones sampled.
update 2022 version: use Set()
let a = ['a', 'a', 'b', 'a'];
let b = ['a', 'a', 'a', 'a'];
const check = (list) => {
const setItem = new Set(list);
return setItem.size <= 1;
}
const checkShort = (list) => (new Set(list)).size <= 1
check(a); // false;
check(b); // true;
checkShort(a); // false
checkShort(b); // true
Update new solution: check index
let a = ['a', 'a', 'b', 'a'];
let b = ['a', 'a', 'a', 'a'];
let check = (list) => list.every(item => list.indexOf(item) === 0);
check(a); // false;
check(b); // true;
Updated with ES6:
Use list.every is the fastest way:
let a = ['a', 'a', 'b', 'a'];
let check = (list) => list.every(item => item === list[0]);
old version:
var listTrue = ['a', 'a', 'a', 'a'];
var listFalse = ['a', 'a', 'a', 'ab'];
function areWeTheSame(list) {
var sample = list[0];
return (list.every((item) => item === sample));
}
If you're already using underscore.js, then here's another option using _.uniq:
function allEqual(arr) {
return _.uniq(arr).length === 1;
}
_.uniq returns a duplicate-free version of the array. If all the values are the same, then the length will be 1.
As mentioned in the comments, given that you may expect an empty array to return true, then you should also check for that case:
function allEqual(arr) {
return arr.length === 0 || _.uniq(arr).length === 1;
}
Shortest answer using underscore/lodash
function elementsEqual(arr) {
return !_.without(arr, arr[0]).length
}
spec:
elementsEqual(null) // throws error
elementsEqual([]) // true
elementsEqual({}) // true
elementsEqual([1]) // true
elementsEqual([1,2]) // false
elementsEqual(NaN) // true
edit:
Or even shorter, inspired by Tom's answer:
function elementsEqual2(arr) {
return _.uniq(arr).length <= 1;
}
spec:
elementsEqual2(null) // true (beware, it's different than above)
elementsEqual2([]) // true
elementsEqual2({}) // true
elementsEqual2([1]) // true
elementsEqual2([1,2]) // false
elementsEqual2(NaN) // true
every() function check if all elements of an array
const checkArr = a => a.every( val => val === a[0] )
checkArr(['a','a','a']) // true
You can use Array.every if supported:
var equals = array.every(function(value, index, array){
return value === array[0];
});
Alternatives approach of a loop could be something like sort
var temp = array.slice(0).sort();
var equals = temp[0] === temp[temp.length - 1];
Or, if the items are like the question, something dirty like:
var equals = array.join('').split(array[0]).join('').length === 0;
Also works.
Yes, you can check it also using filter as below, very simple, checking every values are the same as the first one:
//ES6
function sameValues(arr) {
return arr.filter((v,i,a)=>v===a[0]).length === arr.length;
}
also can be done using every method on the array:
//ES6
function sameValues(arr) {
return arr.every((v,i,a)=>v===a[0]);
}
and you can check your arrays like below:
sameValues(['a', 'a', 'a', 'a']); // true
sameValues(['a', 'a', 'b', 'a']); // false
Or you can add it to native Array functionalities in JavaScript if you reuse it a lot:
//ES6
Array.prototype.sameValues = Array.prototype.sameValues || function(){
this.every((v,i,a)=>v===a[0]);
}
and you can check your arrays like below:
['a', 'a', 'a', 'a'].sameValues(); // true
['a', 'a', 'b', 'a'].sameValues(); // false
You can get this one-liner to do what you want using Array.prototype.every, Object.is, and ES6 arrow functions:
const all = arr => arr.every(x => Object.is(arr[0], x));
Now you can make use of sets to do that easily.
let a= ['a', 'a', 'a', 'a']; // true
let b =['a', 'a', 'b', 'a'];// false
console.log(new Set(a).size === 1);
console.log(new Set(b).size === 1);
I think the simplest way to do this is to create a loop to compare the each value to the next. As long as there is a break in the "chain" then it would return false. If the first is equal to the second, the second equal to the third and so on, then we can conclude that all elements of the array are equal to each other.
given an array data[], then you can use:
for(x=0;x<data.length - 1;x++){
if (data[x] != data[x+1]){
isEqual = false;
}
}
alert("All elements are equal is " + isEqual);
You can convert array to a Set and check its size
In case of primitive array entries, i.e. number, string:
const isArrayWithEqualEntries = array => new Set(array).size === 1
In case of array of objects with some field to be tested for equivalence, say id:
const mapper = ({id}) => id
const isArrayWithEqualEntries = array => new Set(array.map(mapper)).size === 1
You can use this:
function same(a) {
if (!a.length) return true;
return !a.filter(function (e) {
return e !== a[0];
}).length;
}
The function first checks whether the array is empty. If it is it's values are equals..
Otherwise it filter the array and takes all elements which are different from the first one. If there are no such values => the array contains only equal elements otherwise it doesn't.
arr.length && arr.reduce(function(a, b){return (a === b)?a:false;}) === arr[0];
Its Simple.
Create a function and pass a parameter.
In that function copy the first index into a new variable.
Then Create a for loop and loop through the array.
Inside a loop create an while loop with a condition checking whether the new created variable is equal to all the elements in the loop.
if its equal return true after the for loop completes else return false inside the while loop.
function isUniform(arra){
var k=arra[0];
for (var i = 0; i < arra.length; i++) {
while(k!==arra[i]){
return false;
}
}
return true;
}
The accepted answer worked great but I wanted to add a tiny bit. It didn't work for me to use === because I was comparing arrays of arrays of objects, however throughout my app I've been using the fast-deep-equal package which I highly recommend. With that, my code looks like this:
let areAllEqual = arrs.every((val, i, arr) => equal(val, arr[0]) );
and my data looks like this:
[
[
{
"ID": 28,
"AuthorID": 121,
"VisitTypeID": 2
},
{
"ID": 115,
"AuthorID": 121,
"VisitTypeID": 1
},
{
"ID": 121,
"AuthorID": 121,
"VisitTypeID": 1
}
],
[
{
"ID": 121,
"AuthorID": 121,
"VisitTypeID": 1
}
],
[
{
"ID": 5,
"AuthorID": 121,
"VisitTypeID": 1
},
{
"ID": 121,
"AuthorID": 121,
"VisitTypeID": 1
}
]
]
You could use a for loop:
function isEqual(arr) {
var first = arr[0];
for (let i = 1; i < arr.length; i++) {
if (first !== arr[i]) {
return false;
}
}
return true;
}
Underscore's _.isEqual(object, other) function seems to work well for arrays. The order of items in the array matter when it checks for equality. See http://underscorejs.org/#isEqual.
var listTrue = ['a', 'a', 'a', 'a'];
var listFalse = ['a', 'a', 'a', 'ab'];
function areWeTheSame(list) {
var sample = list[0];
return !(list.some(function(item) {
return !(item == sample);
}));
}
function isUniform(array) {
for (var i=1; i< array.length; i++) {
if (array[i] !== array[0]) { return false; }
}
for (var i=1; i< array.length; i++) {
if (array[i] === array[0]) { return true; }
}
}
For the first loop; whenever it detects uneven, returns "false"
The first loop runs, and if it returns false, we have "false"
When it's not return false, it means there will be true, so we do the second loop. And of course we will have "true" from the second loop (because the first loop found it's NOT false)
Create a string by joining the array.
Create string by repetition of the first character of the given array
match both strings
function checkArray(array){
return array.join("") == array[0].repeat(array.length);
}
console.log('array: [a,a,a,a]: ' + checkArray(['a', 'a', 'a', 'a']));
console.log('array: [a,a,b,a]: ' + checkArray(['a', 'a', 'b', 'a']));
And you are DONE !
Another interesting way when you use ES6 arrow function syntax:
x = ['a', 'a', 'a', 'a']
!x.filter(e=>e!==x[0])[0] // true
x = ['a', 'a', 'b', 'a']
!x.filter(e=>e!==x[0])[0] // false
x = []
!x.filter(e=>e!==x[0])[0] // true
And when you don't want to reuse the variable for array (x):
!['a', 'a', 'a', 'a'].filter((e,i,a)=>e!==a[0])[0] // true
IMO previous poster who used array.every(...) has the cleanest solution.
this might work , you can use the comment out code as well that also woks well with the given scenerio.
function isUniform(){
var arrayToMatch = [1,1,1,1,1];
var temp = arrayToMatch[0];
console.log(temp);
/* return arrayToMatch.every(function(check){
return check == temp;
});*/
var bool;
arrayToMatch.forEach(function(check){
bool=(check == temp);
})
console.log(bool);
}
isUniform();
Use index of operator for every item of array
to check if it exists or not. If even one item returns -1 (doesn't exist then it will be false)
nst arr1 = [1, 3, 5];
const arr2 = [5, 7, 9];
const arr3 = [1, 3, 5];
arr1.every(item => arr2.indexOf(item) != -1)
// this will return false
arr1.every(item => arr3.indexOf(item) != -1)
// this will return true
Simple one line solution, just compare it to an array filled with the first entry.
if(arr.join('') === Array(arr.length).fill(arr[0]).join(''))
**// Logical Solution:- Declare global array and one variable(To check the condition) whether all element of an array contains same value or not.**
var arr =[];
var isMatching = false;
for(var i=0;i<arr.length;i++){
if(String(arr[i]).toLowerCase()== "Your string to check"){
isMatching=true;
// Array has same value in all index of an array
}
else{
isMatching=false;
// Array Doesn't has same value in all index of an array
break;
}
}
// **Check isMatching variable is true or false**
if(isMatching){ // True
//If Array has same value in all index, then this block will get executed
}
else{ //False
//If Array doesn't has same value in all index, then this block will get executed
}
I have the associative array:
array["sub2"] = 1;
array["sub0"] = -1;
array["sub1"] = 0;
array["sub3"] = 1;
array["sub4"] = 0;
What is the most elegant way to sort (descending) by its values where the result would be an array with the respective indices in this order:
sub2, sub3, sub1, sub4, sub0
Javascript doesn't have "associative arrays" the way you're thinking of them. Instead, you simply have the ability to set object properties using array-like syntax (as in your example), plus the ability to iterate over an object's properties.
The upshot of this is that there is no guarantee as to the order in which you iterate over the properties, so there is nothing like a sort for them. Instead, you'll need to convert your object properties into a "true" array (which does guarantee order). Here's a code snippet for converting an object into an array of two-tuples (two-element arrays), sorting it as you describe, then iterating over it:
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
a = a[1];
b = b[1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < tuples.length; i++) {
var key = tuples[i][0];
var value = tuples[i][1];
// do something with key and value
}
You may find it more natural to wrap this in a function which takes a callback:
function bySortedValue(obj, callback, context) {
var tuples = [];
for (var key in obj) tuples.push([key, obj[key]]);
tuples.sort(function(a, b) {
return a[1] < b[1] ? 1 : a[1] > b[1] ? -1 : 0
});
var length = tuples.length;
while (length--) callback.call(context, tuples[length][0], tuples[length][1]);
}
bySortedValue({
foo: 1,
bar: 7,
baz: 3
}, function(key, value) {
document.getElementById('res').innerHTML += `${key}: ${value}<br>`
});
<p id='res'>Result:<br/><br/><p>
Instead of correcting you on the semantics of an 'associative array', I think this is what you want:
function getSortedKeys(obj) {
var keys = Object.keys(obj);
return keys.sort(function(a,b){return obj[b]-obj[a]});
}
for really old browsers, use this instead:
function getSortedKeys(obj) {
var keys = []; for(var key in obj) keys.push(key);
return keys.sort(function(a,b){return obj[b]-obj[a]});
}
You dump in an object (like yours) and get an array of the keys - eh properties - back, sorted descending by the (numerical) value of the, eh, values of the, eh, object.
This only works if your values are numerical. Tweek the little function(a,b) in there to change the sorting mechanism to work ascending, or work for string values (for example). Left as an exercise for the reader.
Continued discussion & other solutions covered at How to sort an (associative) array by value? with the best solution (for my case) being by saml (quoted below).
Arrays can only have numeric indexes. You'd need to rewrite this as either an Object, or an Array of Objects.
var status = new Array();
status.push({name: 'BOB', val: 10});
status.push({name: 'TOM', val: 3});
status.push({name: 'ROB', val: 22});
status.push({name: 'JON', val: 7});
If you like the status.push method, you can sort it with:
status.sort(function(a,b) {
return a.val - b.val;
});
There really isn't any such thing as an "associative array" in JavaScript. What you've got there is just a plain old object. They work kind-of like associative arrays, of course, and the keys are available but there's no semantics around the order of keys.
You could turn your object into an array of objects (key/value pairs) and sort that:
function sortObj(object, sortFunc) {
var rv = [];
for (var k in object) {
if (object.hasOwnProperty(k)) rv.push({key: k, value: object[k]});
}
rv.sort(function(o1, o2) {
return sortFunc(o1.key, o2.key);
});
return rv;
}
Then you'd call that with a comparator function.
The best approach for the specific case here, in my opinion, is the one commonpike suggested. A little improvement I'd suggest that works in modern browsers is:
// aao is the "associative array" you need to "sort"
Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
This could apply easily and work great in the specific case here so you can do:
let aoo={};
aao["sub2"]=1;
aao["sub0"]=-1;
aao["sub1"]=0;
aao["sub3"]=1;
aao["sub4"]=0;
let sk=Object.keys(aao).sort(function(a,b){return aao[b]-aao[a]});
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
Besides of this, I provide here a more "generic" function you can use to sort even in wider range of situations and that mixes the improvement I just suggested with the approaches of the answers by Ben Blank (sorting also string values) and PopeJohnPaulII (sorting by specific object field/property) and lets you decide if you want an ascendant or descendant order, here it is:
// aao := is the "associative array" you need to "sort"
// comp := is the "field" you want to compare or "" if you have no "fields" and simply need to compare values
// intVal := must be false if you need comparing non-integer values
// desc := set to true will sort keys in descendant order (default sort order is ascendant)
function sortedKeys(aao,comp="",intVal=false,desc=false){
let keys=Object.keys(aao);
if (comp!="") {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b][comp]-aao[a][comp]});
else return keys.sort(function(a,b){return aao[a][comp]-aao[a][comp]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b][comp]<aao[a][comp]?1:aao[b][comp]>aao[a][comp]?-1:0});
else return keys.sort(function(a,b){return aao[a][comp]<aao[b][comp]?1:aao[a][comp]>aao[b][comp]?-1:0});
}
} else {
if (intVal) {
if (desc) return keys.sort(function(a,b){return aao[b]-aao[a]});
else return keys.sort(function(a,b){return aao[a]-aao[b]});
} else {
if (desc) return keys.sort(function(a,b){return aao[b]<aao[a]?1:aao[b]>aao[a]?-1:0});
else return keys.sort(function(a,b){return aao[a]<aao[b]?1:aao[a]>aao[b]?-1:0});
}
}
}
You can test the functionalities trying something like the following code:
let items={};
items['Edward']=21;
items['Sharpe']=37;
items['And']=45;
items['The']=-12;
items['Magnetic']=13;
items['Zeros']=37;
//equivalent to:
//let items={"Edward": 21, "Sharpe": 37, "And": 45, "The": -12, ...};
console.log("1: "+sortedKeys(items));
console.log("2: "+sortedKeys(items,"",false,true));
console.log("3: "+sortedKeys(items,"",true,false));
console.log("4: "+sortedKeys(items,"",true,true));
/* OUTPUT
1: And,Sharpe,Zeros,Edward,Magnetic,The
2: The,Magnetic,Edward,Sharpe,Zeros,And
3: The,Magnetic,Edward,Sharpe,Zeros,And
4: And,Sharpe,Zeros,Edward,Magnetic,The
*/
items={};
items['k1']={name:'Edward',value:21};
items['k2']={name:'Sharpe',value:37};
items['k3']={name:'And',value:45};
items['k4']={name:'The',value:-12};
items['k5']={name:'Magnetic',value:13};
items['k6']={name:'Zeros',value:37};
console.log("1: "+sortedKeys(items,"name"));
console.log("2: "+sortedKeys(items,"name",false,true));
/* OUTPUT
1: k6,k4,k2,k5,k1,k3
2: k3,k1,k5,k2,k4,k6
*/
As I already said, you can loop over sorted keys if you need doing stuffs
let sk=sortedKeys(aoo);
// now you can loop using the sorted keys in `sk` to do stuffs
for (let i=sk.length-1;i>=0;--i){
// do something with sk[i] or aoo[sk[i]]
}
Last, but not least, some useful references to Object.keys and Array.sort
Here is a variation of ben blank's answer, if you don't like tuples.
This saves you a few characters.
var keys = [];
for (var key in sortme) {
keys.push(key);
}
keys.sort(function(k0, k1) {
var a = sortme[k0];
var b = sortme[k1];
return a < b ? -1 : (a > b ? 1 : 0);
});
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
var value = sortme[key];
// Do something with key and value.
}
No unnecessary complication required...
function sortMapByValue(map)
{
var tupleArray = [];
for (var key in map) tupleArray.push([key, map[key]]);
tupleArray.sort(function (a, b) { return a[1] - b[1] });
return tupleArray;
}
i use $.each of jquery but you can make it with a for loop, an improvement is this:
//.ArraySort(array)
/* Sort an array
*/
ArraySort = function(array, sortFunc){
var tmp = [];
var aSorted=[];
var oSorted={};
for (var k in array) {
if (array.hasOwnProperty(k))
tmp.push({key: k, value: array[k]});
}
tmp.sort(function(o1, o2) {
return sortFunc(o1.value, o2.value);
});
if(Object.prototype.toString.call(array) === '[object Array]'){
$.each(tmp, function(index, value){
aSorted.push(value.value);
});
return aSorted;
}
if(Object.prototype.toString.call(array) === '[object Object]'){
$.each(tmp, function(index, value){
oSorted[value.key]=value.value;
});
return oSorted;
}
};
So now you can do
console.log("ArraySort");
var arr1 = [4,3,6,1,2,8,5,9,9];
var arr2 = {'a':4, 'b':3, 'c':6, 'd':1, 'e':2, 'f':8, 'g':5, 'h':9};
var arr3 = {a: 'green', b: 'brown', c: 'blue', d: 'red'};
var result1 = ArraySort(arr1, function(a,b){return a-b});
var result2 = ArraySort(arr2, function(a,b){return a-b});
var result3 = ArraySort(arr3, function(a,b){return a>b});
console.log(result1);
console.log(result2);
console.log(result3);
Just so it's out there and someone is looking for tuple based sorts.
This will compare the first element of the object in array, than the second element and so on. i.e in the example below, it will compare first by "a", then by "b" and so on.
let arr = [
{a:1, b:2, c:3},
{a:3, b:5, c:1},
{a:2, b:3, c:9},
{a:2, b:5, c:9},
{a:2, b:3, c:10}
]
function getSortedScore(obj) {
var keys = [];
for(var key in obj[0]) keys.push(key);
return obj.sort(function(a,b){
for (var i in keys) {
let k = keys[i];
if (a[k]-b[k] > 0) return -1;
else if (a[k]-b[k] < 0) return 1;
else continue;
};
});
}
console.log(getSortedScore(arr))
OUPUTS
[ { a: 3, b: 5, c: 1 },
{ a: 2, b: 5, c: 9 },
{ a: 2, b: 3, c: 10 },
{ a: 2, b: 3, c: 9 },
{ a: 1, b: 2, c: 3 } ]
A modern approuch to this:
Object.fromEntries(Object.entries(data).sort((a,b)=>b[1]-a[1]).slice(0,5))
P.S: I did an optional slice, you can remove it if you want.
#commonpike's answer is "the right one", but as he goes on to comment...
most browsers nowadays just support Object.keys()
Yeah.. Object.keys() is WAY better.
But what's even better? Duh, it's it in coffeescript!
sortedKeys = (x) -> Object.keys(x).sort (a,b) -> x[a] - x[b]
sortedKeys
'a' : 1
'b' : 3
'c' : 4
'd' : -1
[ 'd', 'a', 'b', 'c' ]