sort object properties and JSON.stringify - javascript

My application has a large array of objects, which I stringify and save them to the disk. Unfortunately, when the objects in the array are manipulated, and sometimes replaced, the properties on the objects are listed in different orders (their creation order?). When I do JSON.stringify() on the array and save it, a diff shows the properties getting listed in different orders, which is annoying when trying to merge the data further with diff and merging tools.
Ideally I would like to sort the properties of the objects in alphabetical order prior to performing the stringify, or as part of the stringify operation. There is code for manipulating the array objects in many places, and altering these to always create properties in an explicit order would be difficult.
Suggestions would be most welcome!
A condensed example:
obj = {}; obj.name="X"; obj.os="linux";
JSON.stringify(obj);
obj = {}; obj.os="linux"; obj.name="X";
JSON.stringify(obj);
The output of these two stringify calls are different, and showing up in a diff of my data, but my application doesn't care about the ordering of properties. The objects are constructed in many ways and places.

The simpler, modern and currently browser supported approach is simply this:
JSON.stringify(sortMyObj, Object.keys(sortMyObj).sort());
However, this method does remove any nested objects that aren't referenced and does not apply to objects within arrays. You will want to flatten the sorting object as well if you want something like this output:
{"a":{"h":4,"z":3},"b":2,"c":1}
You can do that with this:
var flattenObject = function(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object') {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
};
var myFlattenedObj = flattenObject(sortMyObj);
JSON.stringify(myFlattenedObj, Object.keys(myFlattenedObj).sort());
To do it programmatically with something you can tweak yourself, you need to push the object property names into an array, then sort the array alphabetically and iterate through that array (which will be in the right order) and select each value from the object in that order. "hasOwnProperty" is checked also so you definitely have only the object's own properties. Here's an example:
var obj = {"a":1,"b":2,"c":3};
function iterateObjectAlphabetically(obj, callback) {
var arr = [],
i;
for (i in obj) {
if (obj.hasOwnProperty(i)) {
arr.push(i);
}
}
arr.sort();
for (i = 0; i < arr.length; i++) {
var key = obj[arr[i]];
//console.log( obj[arr[i]] ); //here is the sorted value
//do what you want with the object property
if (callback) {
// callback returns arguments for value, key and original object
callback(obj[arr[i]], arr[i], obj);
}
}
}
iterateObjectAlphabetically(obj, function(val, key, obj) {
//do something here
});
Again, this should guarantee that you iterate through in alphabetical order.
Finally, taking it further for the simplest way, this library will recursively allow you to sort any JSON you pass into it: https://www.npmjs.com/package/json-stable-stringify
var stringify = require('json-stable-stringify');
var obj = { c: 8, b: [{z:6,y:5,x:4},7], a: 3 };
console.log(stringify(obj));
Output
{"a":3,"b":[{"x":4,"y":5,"z":6},7],"c":8}

I don't understand why the complexity of the current best answers is needed, to get all the keys recursively. Unless perfect performance is needed, it seems to me that we can just call JSON.stringify() twice, the first time to get all the keys, and the second time, to really do the job. That way, all the recursion complexity is handled by stringify, and we know that it knows its stuff, and how to handle each object type:
function JSONstringifyOrder(obj, space)
{
const allKeys = new Set();
JSON.stringify(obj, (key, value) => (allKeys.add(key), value));
return JSON.stringify(obj, Array.from(allKeys).sort(), space);
}
Or if you want to support older browsers:
function JSONstringifyOrder(obj, space)
{
var allKeys = [];
var seen = {};
JSON.stringify(obj, function (key, value) {
if (!(key in seen)) {
allKeys.push(key);
seen[key] = null;
}
return value;
});
allKeys.sort();
return JSON.stringify(obj, allKeys, space);
}

I think that if you are in control of the JSON generation (and it sounds like you are), then for your purposes this might be a good solution: json-stable-stringify
From the project website:
deterministic JSON.stringify() with custom sorting to get
deterministic hashes from stringified results
If the JSON produced is deterministic you should be able to easily diff/merge it.

You can pass a sorted array of the property names as the second argument of JSON.stringify():
JSON.stringify(obj, Object.keys(obj).sort())

JSON.stringify() replacer function for having object keys sorted in output (supports deeply nested objects).
const replacer = (key, value) =>
value instanceof Object && !(value instanceof Array) ?
Object.keys(value)
.sort()
.reduce((sorted, key) => {
sorted[key] = value[key];
return sorted
}, {}) :
value;
// Usage
// JSON.stringify({c: 1, a: { d: 0, c: 1, e: {a: 0, 1: 4}}}, replacer);
GitHub Gist page here.

Update 2018-7-24:
This version sorts nested objects and supports array as well:
function sortObjByKey(value) {
return (typeof value === 'object') ?
(Array.isArray(value) ?
value.map(sortObjByKey) :
Object.keys(value).sort().reduce(
(o, key) => {
const v = value[key];
o[key] = sortObjByKey(v);
return o;
}, {})
) :
value;
}
function orderedJsonStringify(obj) {
return JSON.stringify(sortObjByKey(obj));
}
Test case:
describe('orderedJsonStringify', () => {
it('make properties in order', () => {
const obj = {
name: 'foo',
arr: [
{ x: 1, y: 2 },
{ y: 4, x: 3 },
],
value: { y: 2, x: 1, },
};
expect(orderedJsonStringify(obj))
.to.equal('{"arr":[{"x":1,"y":2},{"x":3,"y":4}],"name":"foo","value":{"x":1,"y":2}}');
});
it('support array', () => {
const obj = [
{ x: 1, y: 2 },
{ y: 4, x: 3 },
];
expect(orderedJsonStringify(obj))
.to.equal('[{"x":1,"y":2},{"x":3,"y":4}]');
});
});
Deprecated answer:
A concise version in ES2016.
Credit to #codename , from https://stackoverflow.com/a/29622653/94148
function orderedJsonStringify(o) {
return JSON.stringify(Object.keys(o).sort().reduce((r, k) => (r[k] = o[k], r), {}));
}

This is same as Satpal Singh's answer
function stringifyJSON(obj){
keys = [];
if(obj){
for(var key in obj){
keys.push(key);
}
}
keys.sort();
var tObj = {};
var key;
for(var index in keys){
key = keys[index];
tObj[ key ] = obj[ key ];
}
return JSON.stringify(tObj);
}
obj1 = {}; obj1.os="linux"; obj1.name="X";
stringifyJSON(obj1); //returns "{"name":"X","os":"linux"}"
obj2 = {}; obj2.name="X"; obj2.os="linux";
stringifyJSON(obj2); //returns "{"name":"X","os":"linux"}"

A recursive and simplified answer:
function sortObject(obj) {
if(typeof obj !== 'object')
return obj
var temp = {};
var keys = [];
for(var key in obj)
keys.push(key);
keys.sort();
for(var index in keys)
temp[keys[index]] = sortObject(obj[keys[index]]);
return temp;
}
var str = JSON.stringify(sortObject(obj), undefined, 4);

You can sort object by property name in EcmaScript 2015
function sortObjectByPropertyName(obj) {
return Object.keys(obj).sort().reduce((c, d) => (c[d] = obj[d], c), {});
}

You can add a custom toJSON function to your object which you can use to customise the output. Inside the function, adding current properties to a new object in a specific order should preserve that order when stringified.
See here:
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/stringify
There's no in-built method for controlling ordering because JSON data is meant to be accessed by keys.
Here's a jsfiddle with a small example:
http://jsfiddle.net/Eq2Yw/
Try commenting out the toJSON function - the order of the properties is reversed. Please be aware that this may be browser-specific, i.e. ordering is not officially supported in the specification. It works in the current version of Firefox, but if you want a 100% robust solution, you may have to write your own stringifier function.
Edit:
Also see this SO question regarding stringify's non-deterministic output, especially Daff's details about browser differences:
How to deterministically verify that a JSON object hasn't been modified?

I took the answer from #Jason Parham and made some improvements
function sortObject(obj, arraySorter) {
if(typeof obj !== 'object')
return obj
if (Array.isArray(obj)) {
if (arraySorter) {
obj.sort(arraySorter);
}
for (var i = 0; i < obj.length; i++) {
obj[i] = sortObject(obj[i], arraySorter);
}
return obj;
}
var temp = {};
var keys = [];
for(var key in obj)
keys.push(key);
keys.sort();
for(var index in keys)
temp[keys[index]] = sortObject(obj[keys[index]], arraySorter);
return temp;
}
This fixes the issue of arrays being converted to objects, and it also allows you to define how to sort arrays.
Example:
var data = { content: [{id: 3}, {id: 1}, {id: 2}] };
sortObject(data, (i1, i2) => i1.id - i2.id)
output:
{content:[{id:1},{id:2},{id:3}]}

I just rewrote one of mentioned examples to use it in stringify
const stringifySort = (key, value) => {
if (!value || typeof value !== 'object' || Array.isArray(value)) return value;
return Object.keys(value).sort().reduce((obj, key) => (obj[key]=value[key], obj), {});
};
JSON.stringify({name:"X", os:"linux"}, stringifySort);

The accepted answer does not work for me for nested objects for some reason. This led me to code up my own. As it's late 2019 when I write this, there are a few more options available within the language.
Update: I believe David Furlong's answer is a preferable approach to my earlier attempt, and I have riffed off that. Mine relies on support for Object.entries(...), so no Internet Explorer support.
function normalize(sortingFunction) {
return function(key, value) {
if (typeof value === 'object' && !Array.isArray(value)) {
return Object
.entries(value)
.sort(sortingFunction || undefined)
.reduce((acc, entry) => {
acc[entry[0]] = entry[1];
return acc;
}, {});
}
return value;
}
}
JSON.stringify(obj, normalize(), 2);
--
KEEPING THIS OLDER VERSION FOR HISTORICAL REFERENCE
I found that a simple, flat array of all keys in the object will work. In almost all browsers (not Edge or Internet explorer, predictably) and Node 12+ there is a fairly short solution now that Array.prototype.flatMap(...) is available. (The lodash equivalent would work too.) I have only tested in Safari, Chrome, and Firefox, but I see no reason why it wouldn't work anywhere else that supports flatMap and standard JSON.stringify(...).
function flattenEntries([key, value]) {
return (typeof value !== 'object')
? [ [ key, value ] ]
: [ [ key, value ], ...Object.entries(value).flatMap(flattenEntries) ];
}
function sortedStringify(obj, sorter, indent = 2) {
const allEntries = Object.entries(obj).flatMap(flattenEntries);
const sorted = allEntries.sort(sorter || undefined).map(entry => entry[0]);
return JSON.stringify(obj, sorted, indent);
}
With this, you can stringify with no 3rd-party dependencies and even pass in your own sort algorithm that sorts on the key-value entry pairs, so you can sort by key, payload, or a combination of the two. Works for nested objects, arrays, and any mixture of plain old data types.
const obj = {
"c": {
"z": 4,
"x": 3,
"y": [
2048,
1999,
{
"x": false,
"g": "help",
"f": 5
}
]
},
"a": 2,
"b": 1
};
console.log(sortedStringify(obj, null, 2));
Prints:
{
"a": 2,
"b": 1,
"c": {
"x": 3,
"y": [
2048,
1999,
{
"f": 5,
"g": "help",
"x": false
}
],
"z": 4
}
}
If you must have compatibility with older JavaScript engines, you could use these slightly more verbose versions that emulate flatMap behavior. Client must support at least ES5, so no Internet Explorer 8 or below.
These will return the same result as above.
function flattenEntries([key, value]) {
if (typeof value !== 'object') {
return [ [ key, value ] ];
}
const nestedEntries = Object
.entries(value)
.map(flattenEntries)
.reduce((acc, arr) => acc.concat(arr), []);
nestedEntries.unshift([ key, value ]);
return nestedEntries;
}
function sortedStringify(obj, sorter, indent = 2) {
const sortedKeys = Object
.entries(obj)
.map(flattenEntries)
.reduce((acc, arr) => acc.concat(arr), [])
.sort(sorter || undefined)
.map(entry => entry[0]);
return JSON.stringify(obj, sortedKeys, indent);
}

An additional solution that works for nested objects as well:
const myFunc = (key) =>
JSON.stringify(key, (_, v) =>
v.constructor === Object ? Object.entries(v).sort() : v
);
const jsonFunc = JSON.stringify;
const obj1 = {
key1: "value1",
key2: {
key3: "value2",
key4: "value3",
},
};
const obj2 = {
key2: {
key4: "value3",
key3: "value2",
},
key1: "value1",
};
console.log(`JSON: ${jsonFunc(obj1) === jsonFunc(obj2)}`);
console.log(`My: ${myFunc(obj1) === myFunc(obj2)}`);

Works with lodash, nested objects, any value of object attribute:
function sort(myObj) {
var sortedObj = {};
Object.keys(myObj).sort().forEach(key => {
sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : myObj[key]
})
return sortedObj;
}
JSON.stringify(sort(yourObj), null, 2)
It relies on Chrome's and Node's behaviour that the first key assigned to an object is outputted first by JSON.stringify.

After all, it needs an Array that caches all keys in the nested object (otherwise it will omit the uncached keys.) The oldest answer is just plain wrong, because second argument doesn't care about dot-notation. So, the answer (using Set) becomes.
function stableStringify (obj) {
const keys = new Set()
const getAndSortKeys = (a) => {
if (a) {
if (typeof a === 'object' && a.toString() === '[object Object]') {
Object.keys(a).map((k) => {
keys.add(k)
getAndSortKeys(a[k])
})
} else if (Array.isArray(a)) {
a.map((el) => getAndSortKeys(el))
}
}
}
getAndSortKeys(obj)
return JSON.stringify(obj, Array.from(keys).sort())
}

Try:
function obj(){
this.name = '';
this.os = '';
}
a = new obj();
a.name = 'X',
a.os = 'linux';
JSON.stringify(a);
b = new obj();
b.os = 'linux';
b.name = 'X',
JSON.stringify(b);

I made a function to sort object, and with callback .. which actually create a new object
function sortObj( obj , callback ) {
var r = [] ;
for ( var i in obj ){
if ( obj.hasOwnProperty( i ) ) {
r.push( { key: i , value : obj[i] } );
}
}
return r.sort( callback ).reduce( function( obj , n ){
obj[ n.key ] = n.value ;
return obj;
},{});
}
and call it with object .
var obj = {
name : "anu",
os : "windows",
value : 'msio',
};
var result = sortObj( obj , function( a, b ){
return a.key < b.key ;
});
JSON.stringify( result )
which prints {"value":"msio","os":"windows","name":"anu"} , and for sorting with value .
var result = sortObj( obj , function( a, b ){
return a.value < b.value ;
});
JSON.stringify( result )
which prints {"os":"windows","value":"msio","name":"anu"}

If objects in the list does not have same properties, generate a combined master object before stringify:
let arr=[ <object1>, <object2>, ... ]
let o = {}
for ( let i = 0; i < arr.length; i++ ) {
Object.assign( o, arr[i] );
}
JSON.stringify( arr, Object.keys( o ).sort() );

function FlatternInSort( obj ) {
if( typeof obj === 'object' )
{
if( obj.constructor === Object )
{ //here use underscore.js
let PaireStr = _( obj ).chain().pairs().sortBy( p => p[0] ).map( p => p.map( FlatternInSort ).join( ':' )).value().join( ',' );
return '{' + PaireStr + '}';
}
return '[' + obj.map( FlatternInSort ).join( ',' ) + ']';
}
return JSON.stringify( obj );
}
// example as below. in each layer, for objects like {}, flattened in key sort. for arrays, numbers or strings, flattened like/with JSON.stringify.
FlatternInSort( { c:9, b: { y: 4, z: 2, e: 9 }, F:4, a:[{j:8, h:3},{a:3,b:7}] } )
"{"F":4,"a":[{"h":3,"j":8},{"a":3,"b":7}],"b":{"e":9,"y":4,"z":2},"c":9}"

Extending AJP's answer, to handle arrays:
function sort(myObj) {
var sortedObj = {};
Object.keys(myObj).sort().forEach(key => {
sortedObj[key] = _.isPlainObject(myObj[key]) ? sort(myObj[key]) : _.isArray(myObj[key])? myObj[key].map(sort) : myObj[key]
})
return sortedObj;
}

Surprised nobody has mentioned lodash's isEqual function.
Performs a deep comparison between two values to determine if they are
equivalent.
Note: This method supports comparing arrays, array buffers, booleans,
date objects, error objects, maps, numbers, Object objects, regexes,
sets, strings, symbols, and typed arrays. Object objects are compared
by their own, not inherited, enumerable properties. Functions and DOM
nodes are compared by strict equality, i.e. ===.
https://lodash.com/docs/4.17.11#isEqual
With the original problem - keys being inconsistently ordered - it's a great solution - and of course it will just stop if it finds a conflict instead of blindly serializing the whole object.
To avoid importing the whole library you do this:
import { isEqual } from "lodash-es";
Bonus example:
You can also use this with RxJS with this custom operator
export const distinctUntilEqualChanged = <T>(): MonoTypeOperatorFunction<T> =>
pipe(distinctUntilChanged(isEqual));

Here is a clone approach...clone the object before converting to json:
function sort(o: any): any {
if (null === o) return o;
if (undefined === o) return o;
if (typeof o !== "object") return o;
if (Array.isArray(o)) {
return o.map((item) => sort(item));
}
const keys = Object.keys(o).sort();
const result = <any>{};
keys.forEach((k) => (result[k] = sort(o[k])));
return result;
}
If is very new but seems to work on package.json files fine.

Don't be confused with the object monitoring of Chrome debugger. It shows sorted keys in object, even though actually it is not sorted. You have to sort the object before you stringify it.

Before I found libs like fast-json-stable-stringify (haven't tested it in production myself), I was doing it this way:
import { flatten } from "flat";
import { set } from 'lodash/fp';
const sortJson = (jsonString) => {
const object = JSON.parse(jsonString);
const flatObject = flatten(object);
const propsSorted = Object.entries(flatObject).map(([key, value]) => ({ key, value })).sort((a, b) => a.key.localeCompare(b.key));
const objectSorted = propsSorted.reduce((object, { key, value }) => set(key, value, object), {});
return JSON.stringify(objectSorted);
};
const originalJson = JSON.stringify({ c: { z: 3, x: 1, y: 2 }, a: true, b: [ 'a', 'b', 'c' ] });
console.log(sortJson(originalJson)); // {"a":true,"b":["a","b","c"],"c":{"x":1,"y":2,"z":3}}

There is Array.sort method which can be helpful for you. For example:
yourBigArray.sort(function(a,b){
//custom sorting mechanism
});

Related

How to name object keys on a loop in es6 [duplicate]

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.

How can I reorder a javascript object based on the order of an array? [duplicate]

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.

How to properly order the results of an object in Javascript [duplicate]

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.

What's the best way (most efficient) to turn all the keys of an object to lower case?

I've come up with
function keysToLowerCase (obj) {
var keys = Object.keys(obj);
var n = keys.length;
while (n--) {
var key = keys[n]; // "cache" it, for less lookups to the array
if (key !== key.toLowerCase()) { // might already be in its lower case version
obj[key.toLowerCase()] = obj[key] // swap the value to a new lower case key
delete obj[key] // delete the old key
}
}
return (obj);
}
But I'm not sure how will v8 behave with that, for instance, will it really delete the other keys or will it only delete references and the garbage collector will bite me later ?
Also, I created these tests, I'm hoping you could add your answer there so we could see how they match up.
EDIT 1:
Apparently, according to the tests, it's faster if we don't check if the key is already in lower case, but being faster aside, will it create more clutter by ignoring this and just creating new lower case keys ? Will the garbage collector be happy with this ?
The fastest I come up with is if you create a new object:
var key, keys = Object.keys(obj);
var n = keys.length;
var newobj={}
while (n--) {
key = keys[n];
newobj[key.toLowerCase()] = obj[key];
}
I'm not familiar enough with the current inner working of v8 to give you a definitive answer. A few years ago I saw a video where the developers talked about objects, and IIRC
it will only delete the references and let the garbage collector take care of it. But it was years ago so even if it was like that then, it doesn't need to be like that now.
Will it bite you later? It depends on what you are doing, but probably not. It is very common to create short lived objects so the code is optimized to handle it. But every environment has its limitations, and maybe it will bite you. You have to test with actual data.
Using Object.fromEntries (ES10)
Native and immutable solution using the new Object.fromEntries method:
const newObj = Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);
Until that function becomes widely available you could define it yourself with the following polyfill:
Object.fromEntries = arr => Object.assign({}, ...Array.from(arr, ([k, v]) => ({[k]: v}) ));
A nice thing is that this method does the opposite of Object.entries, so now you can go back and forth between the object and array representation.
I'd use Lo-Dash.transform like this:
var lowerObj = _.transform(obj, function (result, val, key) {
result[key.toLowerCase()] = val;
});
Personally, I'd use:
let objectKeysToLowerCase = function (origObj) {
return Object.keys(origObj).reduce(function (newObj, key) {
let val = origObj[key];
let newVal = (typeof val === 'object') ? objectKeysToLowerCase(val) : val;
newObj[key.toLowerCase()] = newVal;
return newObj;
}, {});
}
It's succinct, recurs to handle nested objects and returns a new object rather than modifying the original.
In my limited local testing this function is faster than the other recursive solution currently listed (once fixed). I'd love to benchmark it against the others but jsperf is down at the moment (???).
It's also written in ES5.1 so, according to the docs on MDN, should work in FF 4+, Chrome 5+, IE 9.0+, Opera 12+, Safari 5+ (so, pretty much everything).
Object.keys()
Array. prototype.reduce()
Vanilla JS for the win.
I wouldn't worry too much about the garbage collection aspect of all this. Once all references to the old object are destroyed it will be GC's but the new object will still reference basically all it's properties, so they will not.
Any Functions, Arrays or RegExp will be "copied" across by reference. In terms of memory, even Strings will not be duplicated by this process since most (all?) modern JS engines user string interning. I think that leaves just the Numbers, Booleans and the Objects that formed the original structure left to be GC'd.
Note that (all implementations of) this process will lose values if the original has multiple properties with the same lowercase representation. Ie:
let myObj = { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' };
console.log(myObj);
// { xx: 'There', xX: 'can be', Xx: 'only', XX: 'one!' }
let newObj = objectKeysToLowerCase(myObj);
console.log(newObj);
// { xx: 'one!' }
Of course, sometimes this is exactly what you want.
Update 2018-07-17
A few people have noted the original function doesn't work well with arrays. Here's an expanded, more resilient version. It recurs correctly through arrays and works if the initial value is an array or simple value:
let objectKeysToLowerCase = function (input) {
if (typeof input !== 'object') return input;
if (Array.isArray(input)) return input.map(objectKeysToLowerCase);
return Object.keys(input).reduce(function (newObj, key) {
let val = input[key];
let newVal = (typeof val === 'object') && val !== null ? objectKeysToLowerCase(val) : val;
newObj[key.toLowerCase()] = newVal;
return newObj;
}, {});
};
ES6 version:
Object.keys(source)
.reduce((destination, key) => {
destination[key.toLowerCase()] = source[key];
return destination;
}, {});
The loDash/fp way, quite nice as its essentially a one liner
import {
mapKeys
} from 'lodash/fp'
export function lowerCaseObjectKeys (value) {
return mapKeys(k => k.toLowerCase(), value)
}
Using forEach seems to be a bit quicker in my tests- and the original reference is gone, so deleting the new one will put it in reach of the g.c.
function keysToLowerCase(obj){
Object.keys(obj).forEach(function (key) {
var k = key.toLowerCase();
if (k !== key) {
obj[k] = obj[key];
delete obj[key];
}
});
return (obj);
}
var O={ONE:1,two:2,tHree:3,FOUR:4,Five:5,SIX:{a:1,b:2,c:3,D:4,E:5}};
keysToLowerCase(O);
/* returned value: (Object) */
{
five:5,
four:4,
one:1,
six:{
a:1,
b:2,
c:3,
D:4,
E:5
},
three:3,
two:2
}
Simplified Answer
For simple situations, you can use the following example to convert all keys to lower case:
Object.keys(example).forEach(key => {
const value = example[key];
delete example[key];
example[key.toLowerCase()] = value;
});
You can convert all of the keys to upper case using toUpperCase() instead of toLowerCase():
Object.keys(example).forEach(key => {
const value = example[key];
delete example[key];
example[key.toUpperCase()] = value;
});
Here is easiest solution to convert all the json keys to lower case.
let o = {"Account_Number ":"0102301", "customer_NaME":"name"}
o = Object.keys(o).reduce((c, k) => (c[k.toLowerCase().trim()] = o[k], c), {})
console.log(o)
With TypeScript
/**
* Lowercase the keys of an object
* #example
lowercaseKeys({FOO: true, bAr: false}); // {foo: true, bar: false}
*/
export function lowercaseKeys<T>(object: { [key: string]: T }): { [key: string]: T } {
const result: { [key: string]: T } = {};
for (const [key, value] of Object.entries(object)) {
result[key.toLowerCase()] = value;
}
return result;
}
Usage
lowercaseKeys({FOO: true, bAr: false}); // {foo: true, bar: false}
I used ES6 and TypeScript.
toLowerCaseObject function takes an Array as parameter and looking through Object tree recursively and make every node lowercase:
function toLowerCaseObject(items: any[]) {
return items.map(x => {
let lowerCasedObject = {}
for (let i in x) {
if (x.hasOwnProperty(i)) {
lowerCased[i.toLowerCase()] = x[i] instanceof Array ? toLowerCaseObject(x[i]) : x[i];
}
}
return lowerCasedObject;
});
}
One-liner (only for top level keys):
Object.assign(...Object.keys(obj).map(key => ({[key.toLowerCase()]: obj[key]})))
Converts:
{ a: 1, B: 2, C: { Z: 4 } }
To:
{ a: 1, b: 2, c: { Z: 4 } }
While the ES10 Object.fromentries() method works
const newObj = Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k.toLowerCase(), v])
);
You can similarly use the snippet below for ES2015 and below
this.htmlWorkbookJSON = jsonData.map((element: Object) => {
let entriesArray = Object.entries(element)
const data = new Object()
entriesArray.forEach(([key, value]) => {
data[key.toLocaleLowerCase()] = value;
})
return data
})
This is not the cleanest way but it has worked for my team so it is worth sharing.
I created this method as our backend is running a language that is not case sensitive and the database and backend will produce different key cases. For us, it has worked flawlessly. Mind you we send dates as Strings and we don't send functions.
We have reduced it to this one line.
const toLowerCase = (data) => JSON.parse(JSON.stringify(data).replace(/"([^"]+)":/g, ($0, key) => '"' + key.toString().toLowerCase() + '":'))
We clone the object by using the JSON.parse(JSON.stringify(obj)) method. This produces a string version of the object in the JSON format. While the object is in the string form you can use regex as JSON is a predictable format to convert all keys.
Broken up it looks like this.
const toLowerCase = function (data) {
return JSON.parse(JSON.stringify(data)
.replace(/"([^"]+)":/g, ($0, key) => {
return '"' + key.toString().toLowerCase() + '":'
}))
}
const keysToLowerCase = object => {
return Object.keys(object).reduce((acc, key) => {
let val = object[key];
if (typeof val === 'object') {
val = keysToLowerCase(val);
}
acc[key.toLowerCase()] = val;
return acc;
}, {});
};
Works for nested object.
Consider lowering case just once, storing it in a lowKey var:
function keysToLowerCase (obj) {
var keys = Object.keys(obj);
var n = keys.length;
var lowKey;
while (n--) {
var key = keys[n];
if (key === (lowKey = key.toLowerCase()))
continue
obj[lowKey] = obj[key]
delete obj[key]
}
return (obj);
}
Here's my recursive version based on one of the above examples.
//updated function
var lowerObjKeys = function(obj) {
Object.keys(obj).forEach(function(key) {
var k = key.toLowerCase();
if (k != key) {
var v = obj[key]
obj[k] = v;
delete obj[key];
if (typeof v == 'object') {
lowerObjKeys(v);
}
}
});
return obj;
}
//plumbing
console = {
_createConsole: function() {
var pre = document.createElement('pre');
pre.setAttribute('id', 'console');
document.body.insertBefore(pre, document.body.firstChild);
return pre;
},
info: function(message) {
var pre = document.getElementById("console") || console._createConsole();
pre.textContent += ['>', message, '\n'].join(' ');
}
};
//test case
console.info(JSON.stringify(lowerObjKeys({
"StackOverflow": "blah",
"Test": {
"LULZ": "MEH"
}
}), true));
Beware, it doesn't track circular references, so you can end up with an infinite loop resulting in stack overflow.
For all values:
to_lower_case = function(obj) {
for (var k in obj){
if (typeof obj[k] == "object" && obj[k] !== null)
to_lower_case(obj[k]);
else if(typeof obj[k] == "string") {
obj[k] = obj[k].toLowerCase();
}
}
return obj;
}
Same can be used for keys with minor tweaks.
This is how I do it. My input can be anything and it recuses through nested objects as well as arrays of objects.
const fixKeys = input => Array.isArray(input)
? input.map(fixKeys)
: typeof input === 'object'
? Object.keys(input).reduce((acc, elem) => {
acc[elem.toLowerCase()] = fixKeys(input[elem])
return acc
}, {})
: input
tested using mocha
const { expect } = require('chai')
const fixKeys = require('../../../src/utils/fixKeys')
describe('utils/fixKeys', () => {
const original = {
Some: 'data',
With: {
Nested: 'data'
},
And: [
'an',
'array',
'of',
'strings'
],
AsWellAs: [
{ An: 'array of objects' }
]
}
const expected = {
some: 'data',
with: {
nested: 'data'
},
and: [
'an',
'array',
'of',
'strings'
],
aswellas: [{ an: 'array of objects' }]
}
let result
before(() => {
result = fixKeys(original)
})
it('left the original untouched', () => {
expect(original).not.to.deep.equal(expected)
})
it('fixed the keys', () => {
expect(result).to.deep.equal(expected)
})
})
var aa = {ID:1,NAME:'Guvaliour'};
var bb= {};
var cc = Object.keys(aa);
cc.forEach(element=>{
bb[element.toLowerCase()]=aa[element];
});
cosole.log(bb)
The below code to convert the all key in lower case
array.forEach(item=>{
let data = Object.keys(item).reduce((result, p) => (result[p.toLowerCase().trim()] = item[p], result), {})
if(data.hasOwnProperty(fieldname)){
if(data[fieldname]){
if(!response['data'].includes(data[fieldname].toLowerCase()))
response['data'].push(data[fieldname])
}
}
})
const newObj = {};
for(const key in obj){
newObj[key.toLowerCase()] = obj[key];
}
Most of the above answers do not handle null and undefined values. To get around it why not use the transform helper function from lodash?
const query = {
Company: 'GH Works',
Items: {
Construction: 'FB',
LineItems: {
Quantity: '100',
QUALity: 'checked'
}
}
}
function deepLowercaseKeys(hash) {
return _.transform(hash, function(result, value, key) {
const valueIsObject = typeof value === 'object';
result[key.toLowerCase()] = valueIsObject ? deepLowercaseKeys(value) : value;
});
}
console.log(deepLowercaseKeys(query))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Additionally, you can customize the function and then use it to transform the object in any way you like.
const query = {
Company: 'GH Works',
Items: {
Construction: 'FB',
LineItems: {
Quantity: '100',
QUALity: 'checked'
}
}
}
// Base function
function deepTransform(hash, callback) {
return _.transform(hash, function(result, value, key) {
if (typeof value === 'object') {
return callback(result, deepTransform(value, callback), key)
}
callback(result, value, key)
})
}
// Custom function (can be anything)
function appendHello(hash) {
return deepTransform(hash, function(result, value, key) {
result[`${key}_hello`.toLowerCase()] = value;
})
}
console.log(appendHello(query))
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
const objectToLowercase = (data) => {
const values = Object.values(data);
if (values.length === 0) {
return data;
}
return Object.keys(data).reduce((toLowerKeyObj, key) => {
const isObject = typeof data[key] === 'object';
const isArray = Array.isArray(data[key]);
let value = null;
if (isObject) {
if (!isArray) {
value = objectToLowercase(data[key]);
}
}
if (isArray) {
value = data[key].map(_value => {
return objectToLowercase(_value);
});
}
toLowerKeyObj[key.toLowerCase()] = isObject ? value : data[key];
return toLowerKeyObj;
}, {});
};

Sort JavaScript object by key

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.

Categories