0

I am trying to custom sort a JavaScript object but not able to get how we can do this in a right way. Say I am having an object like

var test = {
  'yellow': [],
  'green': [],
  'red': [],
  'blue': []
}

And I have an array with values of : var arr = ['red', 'green', 'blue', 'yellow'];

So after sorting, I want to output in the order which is specified in array like

var test = {
  'red': [],
  'green': [],
  'blue': [],
  'yellow': []
}

But for some reason, I am not able to achieve that. What am trying to do here is loop and sort but it sorts in A-Z pattern and not in the order I've specified the array in. Also, you might ask that am not even using my array in the sort function but am not getting an exact way to achieve this.

var test = {
  'yellow': [],
  'green': [],
  'red': [],
  'blue': []
}

var keys = Object.keys(test);

console.log(keys.sort());  //["blue", "green", "red", "yellow"] which is not ordered nor it's an object

Any directions will he helpful.


Note: I am having this specific requirement because am using HandleBars with default {{#each}} block, but I want to loop the inner objects in that order. I can loop the objects in Handlebars and pass them to the template but than am not using the power of template engine. I want Handlebars to loop them or am I missing something? Is it fine if I loop the objects and pass the entire markup to handlebars template.

Learner
  • 21
  • 1
  • 3
  • 2
    Objects have no order in JavaScript. "Sorting an object" is meaningless. – Niet the Dark Absol May 05 '16 at 17:05
  • @NiettheDarkAbsol I am passing my object in HandleBars which works well if I pass the ordered object. – Learner May 05 '16 at 17:06
  • 1
    As soon as an object enters JavaScript, it has no order any more. For evidence of this, try the following in Chrome: `console.dir({b:1,a:2})` - you will get `{a:2,b:1}` as output, because Chrome presents objects with keys in alphabetical order for easier debugging. It can do this because of the lack of inherent order in objects. – Niet the Dark Absol May 05 '16 at 17:07
  • Please use the search before you ask a new question. – Felix Kling May 05 '16 at 17:10
  • 1
    @FelixKling the question you tagged is not the same, that is normal sorting, what am asking is for custom sorting. I did searched before asking this question. Please read the question before you close them. – Learner May 05 '16 at 17:11
  • 2
    This is one of those times where one is trying to solve problem A, decides on a course of action B, gets stuck, and then tries to get help with B instead of asking for help with A. @Learner you should instead ask for help with your problem A, which seems to be something like 'how to display my JS object contents in a Handlebars template, ordered'. – Thernys May 05 '16 at 17:11
  • @Learner: Since you cannot "sort" object properties, it doesn't really matter what kind of sorting you are looking for. "Custom sort" can always be achieved by passing a callback to `.sort`. – Felix Kling May 05 '16 at 17:12
  • @Thernys I'll do that, thanks for your help, but I wanted to understand that in JS and not in Handlebars directly hence this question. – Learner May 05 '16 at 17:12
  • How to sort something by another array has also been asked multiple times: [`[javascript] sort array by order of other array`](https://stackoverflow.com/search?q=%5Bjavascript%5D+sort+array+by+order+of+other+array). – Felix Kling May 05 '16 at 17:15
  • @FelixKling Could `Map()` be used? Did not notice `Map()` being utilized at linked Question – guest271314 May 05 '16 at 17:16
  • 1
    @guest271314: Sure, but only if the order is known beforehand (which is the case here). But that also only works if the function receiving the data knows how to deal with `Map`s. And then again, if it's your code that iterates over the `Map`, you might as well iterate over the key array and simply access the object properties in that order. – Felix Kling May 05 '16 at 17:19
  • 1
    @Thernys Also known as the [XY problem](http://meta.stackexchange.com/q/66377/234299). – ThisSuitIsBlackNot May 05 '16 at 17:19
  • @ThisSuit Thanks, the name escaped me so I had to launch into the long version. – Thernys May 05 '16 at 17:20
  • @guest271314: I'm not convinced reopening the question was the right call. – Felix Kling May 05 '16 at 17:21
  • Duplicate of [Sort JavaScript object by key](https://stackoverflow.com/questions/5467129/sort-javascript-object-by-key) – Felix Kling May 05 '16 at 17:24
  • @FelixKling Only voted to reopen because `Map` did not appear to be mentioned at linked Question. Was this not appropriate? – guest271314 May 05 '16 at 17:25
  • 1
    @guest271314: Why didn't you post the answer in the linked question then? We don't need more of these questions (IMO). – Felix Kling May 05 '16 at 17:26
  • @FelixKling _"We don't need more of these questions (IMO)."_ Got it. – guest271314 May 05 '16 at 19:24

3 Answers3

3

JavaScript objects are hashes and therefore inherently un-ordered. You cannot make an object with properties in any given order. If you are receiving an ordering when you enumerate the keys, it is purely coincidental, or better said, an implementation detail of the JavaScript engine.

You'd have to use an array of objects to achieve something like what you want to do.

In other words, it is not possible with the data structure you have chosen.

Brian Genisio
  • 46,643
  • 16
  • 121
  • 163
  • So as I said, I am using Handlebars, where I loop an object with `each` but I want to loop that in the above order, so do I need to write a helper for that, and generate markup in the helper? If that's the thing than it is meaningless to use templating as all the loops are running on my end. – Learner May 05 '16 at 17:08
  • If you want to loop over something in order, you must pass in an array. An object will not give you the results you want. – Brian Genisio May 05 '16 at 17:09
  • Thanks for your help, I will mark your answer as correct once system allows me to – Learner May 05 '16 at 17:13
1

You could use Map()

A Map object iterates its elements in insertion order

var arr = ['red', 'green', 'blue', 'yellow'];

var map = new Map();

arr.forEach(function(val, index) {
  var obj = {};
  obj[val] = [];
  map.set(index, obj)
});

console.log(map)
guest271314
  • 1
  • 10
  • 82
  • 156
0

May be you could change this using JSON.stringify()

do like

var json = {     "name": "David",     "age" : 78,     "NoOfVisits" : 4   };
console.log(json);
//outputs - Object {name: "David", age: 78, NoOfVisits: 4}
//change order to NoOfVisits,age,name

var k = JSON.parse(JSON.stringify( json, ["NoOfVisits","age","name"] , 4));
console.log(k);
//outputs - Object {NoOfVisits: 4, age: 78, name: "David"} 

put the key order you want in an array and supply to the function. then parse the result back to json.

hussain
  • 324
  • 3
  • 7