0

This is a follow up to a previous question I asked:

Sort JSON response by key value

So I know that objects cannot be sorted using the .sort method and if I push each object into an array, I can sort it the way I want.

Why does .sort not work on this:

{ A:{...}, B:{...}, C:{...} }

but works on this:

[ {...}, {...}, {...} ]

It's still accessing and working with object properties in both examples, right?

Here's some code:

var query = {
  "736":{
    ns: 42,
    pageid: 12,
    lang: "en",
    index: 3
  },
  "421":{
    ns: 12,
    pageid: 36,
    lang: "en",
    index: 4
  },
  "102":{
    ns: 2,
    pageid: 19,
    lang: "en",
    index: 1
  }
};

var queryArr = [{ns: 42, pageid: 12, lang: "en", index: 3}, {ns: 12, pageid: 36, lang: "en", index: 4}, {ns: 2, pageid: 19, lang: "en", index: 1}];

query is an object with multiple objects in it, and queryArr is an arry with multiple objects in it. If I wanted to sort query by its index key's value, I'd have to convert it to an arry first, and then run .sort on that array, correct?

What I want to know is why. What prevents query from being sorted, but allows the objects inside queryArr to be sorted? They're both still objects right? The only difference is the outer body is an object in the first, and an array in the second - but it's still working with objects when sorting.

My sort function still referneces the index using the object property accessor:

queryArr.sort(function(i,j){
  return j.index - i.index;
});
firefiber
  • 155
  • 1
  • 2
  • 10
  • 2
    Because an Array represents a list of things. And order is one of the properties of lists; that's how we as humans think about lists. Whereas an object is a collection of values referenced/associated by a name or label, and such a collection doesn't have any intrinsic order. – Thomas Jan 27 '18 at 12:28
  • 1
    Think of object properties in terms of real world properties, like a pen has a colour, a type (ballpoint, felt, fountain), a length, a shape etc.. Now try and imagine why on earth you'd want to sort those properties, but more so, if you did somehow sort them would it make any difference to the pen? If you want things you can sort then you do need arrays. Object properties are just completely different things. – Reinstate Monica Cellio Jan 27 '18 at 12:31
  • @Archer completely agree, except, with an array of objects, aren't I still working with object properties? Like in the example, an array of this form: `[{...},{...},{...}] ` where each {...} has multiple properties, and I use `.sort`, isn't it still working with object properties? – firefiber Jan 27 '18 at 12:39
  • 1
    @firefiber You're sorting the pencils (objects) using one or multiple properties of the pencils (length, color, ...). But you're _not_ sorting the properties of the pencils. – Andreas Jan 27 '18 at 12:50

2 Answers2

0

Arrays are a special way of sequentially storing data. In the earliest implementations, this would be done by actually storing the array objects sequentially in memory. And resorting would actually physically move the objects in memory. So in your example where you have indices 102, 421, and 736. If you translated this to an array, you would actually have an array of length 737. 0 to 101 would be undefined, then you would have your object at 102. 103 to 420 would be undefined, then object 421. Et cetera.

Good to note that in your example when you translated your object into an array, you lost your keys (102, 421, 736). They simply became (0,1,2). In your example maybe this was okay, but if you had an object with properties like width, height, length, having these replaced with simple array indices like 0,1,2 would be a pretty significant loss of information.


Objects don't work the same way at all. They are not designed to store data sequentially, but hierarchically. So you can have a key 102 that points to an object, but you don't have to have keys 0-101. And key 102 doesn't designate the "order" of the item. It's just a name, and it could just as easily be length or fred or green as 102.

This mirrors reality. For example you might have an array to store a group of people, perhaps starting in order of age. And you could re-sort the list by different properties, like alphabetical by last name, or by height, etc.

But if we look at the objects within that array, it really makes no sense to talk about the order of firstName, lastName, height, weight, age, etc. There isn't really any "order" to speak of: weight doesn't have to come before height, or vice versa. And some people may like to see Last,First, while others prefer First Last. These properties are things we mostly want to be able to access directly by name, so an array isn't really ideal. We want named properties. Hence an object. Don't be confused just because you chose numbers as your property names...they're still names, not indices.


However it is of course possible to iterate all the properties of an object, and it is even possible to control the order in which you iterate them. Traditionally in javascript this iteration was done with the for...in syntax, which goes all the way back to es1. But you couldn't control the order in which the object's keys were iterated. To control order we would have to use for...in to populate an array of keys, then sort the array, then re-loop over the array.

However, it is possible in the newer es6 javascript world to iterate in some great new ways. For example, you can use Object.keys() to get an array of all the object keys (property names), and then you could sort this array. Saves the step of populating an array with for...in.

Another more advanced possibility in es6 (which uses Object.keys) is to actually make the object itself iterable by adding a Symbol.iterator. Again, this only works in es6+.

However the Symbol.iterator gives you a lot of power. This is what it looks like:

query[Symbol.iterator] = function*() {
    let properties = Object.keys(this).sort();
    for(let p of properties) {
        yield {key:p, value:this[p]}
    }
}

Once you add this iterator to the object, now you can use things like for...of. And in this example I added a .sort(), so this would iterate over the object's properties in ascending numeric order by key: 102, 421, 736. And since we are yielding an object with key and value, we are still able to see the key value, which we would NOT have if we had just translated to an array.

for(let {key,value} of query) {
    console.log(key);
}
David784
  • 7,031
  • 2
  • 22
  • 29
0

Array object is object where the positive integer keys are used:

a = [, 1]
a[.1] = .1
a[-1] = -1

console.log( a )
console.log( { ...a } )

If the order of the properties can't be guaranteed, then for example array object [0, 1] can be stored as { "0": 0, "1": 1 } or { "1": 1, "0": 0 }.

Most array looping constructs will look for the "0" property before the "1" property, so the property order doesn't really matter.

Sorting array doesn't change it's properties order, but swaps the values associated with the properties.

Slai
  • 22,144
  • 5
  • 45
  • 53