Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript in IE8: how to sort array of objects by alphanumeric property

I've got an array of Javascript objects that I'd like to cross-compatibly sort by a property that is always a positive integer with an optional single letter at the end. I'm looking for a solution that works in at least Firefox 3 and Internet Explorer 8. The closest I've come to such a sort function is the following:

var arrayOfObjects = [{id: '1A', name: 'bar', size: 'big'}, {id: '1C', name: 'bar', size: 'small'}, {id: '1', name: 'foo', size: 'big'}, {id: '1F', name: 'bar', size: 'big'}, {id: '1E', name: 'bar', size: 'big'}, {id: '1B', name: 'bar', size: 'small'}, {id: '1D', name: 'bar', size: 'big'}, {id: '1G', name: 'foo', size: 'small'},  {id: '3', name: 'foo', size: 'small'}, {id: '23', name: 'foo', size: 'small'}, {id: '2', name: 'foo', size: 'small'}, {id: '1010', name: 'foo', size: 'small'}, {id: '23C', name: 'foo', size: 'small'}, {id: '15', name: 'foo', size: 'small'}]

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

After being so sorted, printing out arrayOfObjects gives:

1, foo, big
1010, foo, small
15, foo, small
1A, bar, big
1B, bar, small
1C, bar, small
1D, bar, big
1E, bar, big
1F, bar, big
1G, foo, small
2, foo, small
23, foo, small
23C, foo, small
3, foo, small

However, I would like arrayOfObjects to print out in the order below:

1, foo, big
1A, bar, big
1B, bar, small
1C, bar, small
1D, bar, big
1E, bar, big
1F, bar, big
1G, foo, small
2, foo, small
3, foo, small
15, foo, small
23, foo, small
23C, foo, small
1010, foo, small

Given that, how could I fix the above function so that the objects sort by number as primary key and letter as secondary key? Thanks in advance for any help.

like image 538
jqp Avatar asked Sep 28 '10 23:09

jqp


1 Answers

arrayOfObjects.sort((function() {
  var splitter = /^(\d+)([A-Z]*)/;
  return function(a, b) {
    a = a.id.match(splitter); b = b.id.match(splitter);
    var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10);
    if (anum === bnum)
      return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0;
    return anum - bnum;
  }
})());

the idea is to split the keys into the numeric and string parts.

edit (oops got the "match" call backwards)

edit again @Ryan Tenney wisely suggests that the anonymous outer function isn't really necessary:

arrayOfObjects.sort(function(a, b) {
  var splitter = /^(\d+)([A-Z]*)/;
  a = a.id.match(splitter); b = b.id.match(splitter);
  var anum = parseInt(a[1], 10), bnum = parseInt(b[1], 10);
  if (anum === bnum)
    return a[2] < b[2] ? -1 : a[2] > b[2] ? 1 : 0;
  return anum - bnum;     
});

a little simpler.

like image 138
Pointy Avatar answered Nov 04 '22 06:11

Pointy