2

Before I sort I can access array values by key correctly.

var a=[];
a['1']={'id':'1','aaa':'xxx'}
a['2']={'id':'2','bbb':'yyy'}

document.write(a['1'].id+' '+a['2'].id+'<br>')

After the sort, the keys turn into indexes:

a.sort(function(a, b) {
   var x = a.id;
   var y = b.id;
   return ((x < y) ? -1 : ((x > y) ? 1 : 0));
});

alert('a["1"]='+a['1'].id+'\n\na["2"]='+a['2'])

a["2"] becomes undefined. Where is the problem? Is sorting incorrect?

Here is example: http://jsfiddle.net/TJLtS/1/

Phrogz
  • 296,393
  • 112
  • 651
  • 745
Vad
  • 3,658
  • 8
  • 46
  • 81
  • 1
    Note: in JavaScript, `a["1"]` is the same as `a[1]`; there's no reason to use the quotes. – Phrogz Feb 17 '12 at 17:54

2 Answers2

3

Your problem is that arrays in JavaScript are 0-based, not 1-based. After you sort, your first element is a[0] and your second is a[1]. There is no a[2], after sorting.

You could see this yourself if you would open your Developer Tools in your browser—all modern browsers have them; Google if you need help finding it—and adding the code console.log(a) after sorting. Using alert is about the most painful and least efficient possible way to debug your code.

Here's an updated version of your script, working: http://jsfiddle.net/TJLtS/2/

Also, for future reference you may wish to declare your object literals more simply:

var a = [
  {id:'1', aaa:'xxx'},     // This is a[0]
  {id:'2', bbb:'yyy'}      // This is a[1]
];

As you can see, keys that are legal identifiers do not need to be quoted in object literals.


Edit Here are two alternatives you might be interested in, depending on your needs:

Keep All Objects in a Sorted Array

var objects = [
  {id:"a1", name:"Jim"},
  {id:"a2", name:"Zed"}, 
  {id:"a3", name:"Bob"}, 
];
objects.sort(function(o1,o2){
  var n1 = o1.name, n2 = o2.name;
  return n1<n2 ? -1 : n1>n2 ? 1 : 0;
});
for (var i=0,len=objects.length; i<len; ++i ){
  console.log( objects[i].id );
}
// Result:
// a3, a1, a2

Keep All Objects in a Hash, with Separate Ordering

var objects = {
  a1: {id:"a1", name:"Jim"},
  a2: {id:"a2", name:"Zed"}, 
  a3: {id:"a3", name:"Bob"}, 
};

// Easily look up an object by id (can't do this as easily or fast with array)
var id = "a2";
console.log( objects[id] ); // {id:"a2", name:"Zed"}

// Create an array just the ids
var ids = Object.keys(objects);

// Sort the array of ids based on properties of the objects the represent
ids.sort(function(id1,id2){
  var n1 = objects[id1].name, n2=objects[id2].name;
  return n1<n2 ? -1 : n1>n2 ? 1 : 0;
});

// Iterate the sorted array and use each key to find the object
for (var i=0,len=ids.length; i<len; ++i){
  console.log( objects[ids[i]].name );
}
// Result:
// Bob, Jim, Zed
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • Thank you, but I need a multidimensional array where a['1'] is the first element. It can be a['589'] as the first array. – Vad Feb 17 '12 at 18:11
  • 2
    @Vad That does not make any sense. a) As I already commented, `a["1"]` and `a[1]` are _exactly the same_ in JavaScript. b) Once you sort an array, the first object will always be at index `0` (even if that object may have a property like `id:589`). – Phrogz Feb 17 '12 at 18:13
  • OK I got it but I do need a so-called JavaScript hash map. How to achieve that? Can't I use numbers as the keys? – Vad Feb 17 '12 at 18:18
  • 1
    See my other comment; yes, you can use any value as the keys (including things that are not legal identifiers, such as numbers). However, a hash map does not have ordering, and cannot be sorted. It may be that you want a hash of objects for fast lookup, and a separate array of the keys ordered a particular way for particular iteration. If you do not explain in your question what goal you are trying to accomplish, we can only vaguely guess at how to help. – Phrogz Feb 17 '12 at 18:20
1

Java script arrays starts with 0. Your 0th element is now sorted to be last.

Note that there is no "multidimensional array" in your sample - just array of objects.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • I need a multidimensional array where a['1'] is the key - that's why I use quotes. It happens that it looks like index but it can be anything such as a['1A'] – Vad Feb 17 '12 at 18:09
  • @Vad The first dimension is the ordering of objects in your array. The objects themselves do not contain any ordering amongst the properties, and thus you have a simple array of objects, not a multi-dimensional array (which one might call an array of arrays). – Phrogz Feb 17 '12 at 18:11
  • @Vad - please check out http://stackoverflow.com/questions/1520714/javascript-sorting-collection-which-is-not-an-array since you "array" is not really array. – Alexei Levenkov Feb 17 '12 at 18:15
  • maybe I got confused with definition of multi-dimensional array. my array is a 'hash map' (note quotes). – Vad Feb 17 '12 at 18:16
  • @Vad If you must have ordering of your objects, you do want an array. If you want a hash, then you want to use an object, e.g. `var o = { a1: { id:'a1', aaa:'xxx' }, b2: { id:'b2', bbb:'yyy' } }; alert(o.a1);` However, you cannot sort an object; the properties have no intrinsic ordering. – Phrogz Feb 17 '12 at 18:17
  • The goal is to have a collection of data which can be sorted and printed in sorted order. So if I want to sort, I must have an array of objects (a[0] instead of a['1']) but for fast lookup I seem to not be able to use JS hash map. True? – Vad Feb 17 '12 at 18:27
  • @Vad, (Phrogz answer covers all). Kind of hard to say if your statement true or false. `a[0]` and `a['1']` are elements of an array (assuming a is defined as `a=[]`), so "instead of " is strange there. Hash map(table)/dictionary normally do not define sort order (i.e. in JavaScript object is hash map and does not define order for properties). If you need both - just have 2 way to refer to the same object - array for sorting/indexing and hash map for access by a key. – Alexei Levenkov Feb 17 '12 at 19:00