0

I have an object

{
"William_Hill":{},
"bet365":{},
"royal panda":{"pay":0},
"karamba":{"roller":0,"braned":0,"pay":0},
"betfred":{"braned":0}
}

and want to sort it by the nuber of properties, so the result shoul look like this and it must be an object

 {
    "William_Hill":{},
    "bet365":{},
    "betfred":{"braned":0},
    "royal panda":{"pay":0},
    "karamba":{"roller":0,"braned":0,"pay":0}
}

I have sorted it like this one but the result is an array

var keysSorted = Object.keys(resultArray).sort(function(a,b){
    return Object.keys(resultArray[a]).length-Object.keys(resultArray[b]).length;
});
SERG
  • 3,383
  • 7
  • 34
  • 67
  • Unfortunately, there is no straight forward way to do this :( – Rohit416 Jul 01 '16 at 11:26
  • that is the best you get. you can not, actually, sort an object. – Nina Scholz Jul 01 '16 at 11:26
  • @Rohit416: There is *now*, in ES2015. – T.J. Crowder Jul 01 '16 at 11:26
  • As said, you cant guarantee the order of props in an object. But since 2015 there is the 'Map' object that might help you.. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map – Matt Bryson Jul 01 '16 at 11:28
  • @MattBryson: That's no longer true, as of ES2015. – T.J. Crowder Jul 01 '16 at 11:28
  • @T.J.Crowder Oh well, I should go and take a look then! – Rohit416 Jul 01 '16 at 11:29
  • @T.J.Crowder: Uh, [still not really](http://stackoverflow.com/q/30076219/1048572). If you want something ordered, use a `Map`. – Bergi Jul 01 '16 at 11:35
  • "*the result should look like this and it must be an object*" - why? What difference does it make? – Bergi Jul 01 '16 at 11:36
  • @Bergi well as it is not possible, than it can be anything – SERG Jul 01 '16 at 11:38
  • @Bergi: As you know, properties **do** now have order, just not in `for-in` or `Object.keys`. Saying otherwise is simply inaccurate. – T.J. Crowder Jul 01 '16 at 11:39
  • @Bergi If you don't use number-like keys, `Symbols` and don't rely on `Object.keys` (and thus on for..in) then the specified order in ES2015 is equivalent to the insertion order. –  Jul 01 '16 at 11:41
  • @Bergi Why did the ES2015 spec introduce an order anyway? Why this restriction? –  Jul 01 '16 at 11:43
  • @LUH3417, T.J.Crowder: Yes, that's what the linked question says. However, the spec only defines an order for consistency purposes, not intending for objects being sorted. So even while it might be possible, one still should not do it. – Bergi Jul 01 '16 at 11:45
  • @Bergi: Indeed, one shouldn't. Which is very different from "not really." – T.J. Crowder Jul 01 '16 at 11:47
  • @Bergi Got it - it's still quite a mess and confusing. –  Jul 01 '16 at 11:48
  • @SERG: Why do you think you want to put the properties in an order? – T.J. Crowder Jul 01 '16 at 11:48

2 Answers2

1

Until ES2015, JavaScript object properties had no defined order. They do now, but that order isn't respected by for-in or Object.keys, only by new features like Object.getOwnPropertyNames. It's also more complicated than it seems and of very limited use.

There's almost never any good reason to try to put an object in a specific order. If you want order, use an array, or in ES2015 use a Map (see below).

But that said, in ES2015, with property names like yours, it's possible: The only way to set the order of the properties in an object is to determine the order in which they're created, which (for properties that aren't array indexes) is the order they'll be in. So you can do this by getting all the property names, determining the order you want them in, and then creating a new object, adding the properties in that order.

Beware, though, that certain classes of property names (what we call "array indexes") are sorted differently. None of your property names meets the definition, but (say) "123" would.

Here's an example of doing it, if you really want to (I've happily used ES2015's arrow functions, since this only works in ES2015):

// The object
let obj = {
"William_Hill":{},
"bet365":{},
"royal panda":{"pay":0},
"karamba":{"roller":0,"braned":0,"pay":0},
"betfred":{"braned":0}
};

// Get its names, sort them by how may sub-props there are
let names = Object.keys(obj);
names.sort((a, b) => Object.keys(obj[a]).length - Object.keys(obj[b]).length);

// Get the new object
let newObj = names.reduce((acc, name) => {
  acc[name] = obj[name];
  return acc;
}, {});

// Show its property names
console.log(Object.getOwnPropertyNames(newObj));

Naturally, that can be shorter, I've kept the steps separate for clarity. Similarly, I go back and forth on that use of reduce, you could do the last bit like this instead:

// Get the new object
var newObj = {};
names.forEach(name => {
  acc[name] = obj[name];
});

Here's an example using a Map instead, which offers much less complicated ordering of entries (no worries about "array indexes"):

// The object
let obj = {
"William_Hill":{},
"bet365":{},
"royal panda":{"pay":0},
"karamba":{"roller":0,"braned":0,"pay":0},
"betfred":{"braned":0}
};

// Get its names, sort them by how may sub-props there are
let names = Object.keys(obj);
names.sort((a, b) => Object.keys(obj[a]).length - Object.keys(obj[b]).length);

// Get the map
let map = new Map();
names.forEach(name => {
  map.set(name, obj[name]);
});

// Show its property names
console.log(Array.from(map.keys()));
T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
  • The first thought when i saw this thread was to get an array using `Object.keys` then sort it to _create a new object with the property with desired sort order using the sorted array (but not in ES2015 style)_. Those arrow functions are awesome :) – Rohit416 Jul 01 '16 at 11:48
  • @Rohit416: Yup. I love a lot about ES2015, but arrow functions are really, really high on the list. :-) – T.J. Crowder Jul 01 '16 at 11:49
-1

Dict object in Javascript cannot guarantee the element order. So maybe you can only use an array to handler the sorted result.

Reference: Does JavaScript Guarantee Object Property Order?

Community
  • 1
  • 1
Shu Peng
  • 19
  • 2