0

I have an array of objects.

In each object, I'm targeting a property called "myLevel". The values for this property vary in the following string syntax:

 [
 {myLevel : 'CAT I #4'},
 {myLevel : 'CAT I #6'},
 {myLevel : 'CAT I #2'},
 {myLevel : 'CAT II #15'},
 {myLevel : 'CAT III #1'},
 {myLevel : 'CAT II #7'},

   ]

How can I sort the array so that the objects are rearranged in ascending order like so:

[
 {myLevel : 'CAT I #2'},
 {myLevel : 'CAT I #4'},
 {myLevel : 'CAT I #6'},
 {myLevel : 'CAT II #7'},
 {myLevel : 'CAT II #15'},
 {myLevel : 'CAT III #1'}
   ] 
Kode_12
  • 4,506
  • 11
  • 47
  • 97
  • A similar question to this has already been asked: http://stackoverflow.com/questions/1129216/sort-array-of-objects-by-string-property-value-in-javascript – Richard Chassereau Jul 27 '16 at 00:50
  • Can the `CAT` values with roman numerals go up higher than `III`? If you need to allow for `VIII` being less than `IX`, etc. that complicates things. – nnnnnn Jul 27 '16 at 01:06
  • nope, it's capped at III, that would be painful – Kode_12 Jul 27 '16 at 01:12
  • If those are Roman numbers, then this will need a roman number parser to get true roman numeral order. Yuck. – jfriend00 Jul 27 '16 at 01:19

4 Answers4

1

Use Array.sort, and in the passed function, split the strings by the # sign, compare the first half as string, if even, compare second half as int with call parseInt.
In reality, this will be slow if there are a lot of records. You should really store the records as an object with 2 integers for cat and level. Thia will make sorting more efficient. You can override the toString function to display it the way you like.

lionscribe
  • 3,413
  • 1
  • 16
  • 21
  • As mtioned in other comments, the string compare of the first half will only work if the Roman numerals don't go too high, that is they don't reach they get to the XL (40). – lionscribe Jul 27 '16 at 02:31
1

Use RegEx to match the parts, then check those parts individually

var arr = [
 {myLevel : "CAT I #4"},
 {myLevel : "CAT I #6"},
 {myLevel : "CAT I #2"},
 {myLevel : "CAT II #15"},
 {myLevel : "CAT III #1"},
 {myLevel : "CAT II #7"}
];

var sorted = arr.sort(function(a,b){
 var left = a.myLevel.match(/CAT (I+) #([0-9]+)/);
 var right = b.myLevel.match(/CAT (I+) #([0-9]+)/);
 if(left[1].length==right[1].length){
  return left[2]-right[2];
 }else return left[1].length-right[1].length;
});

The match returns

[0] whole matched string
[1] all the `I`'s
[2] the number after the #

The first if is to check if the I count is the same, if it is we need to check by the number.

If we need to check by the number, we just need to return the difference between them.

If we don't need to check by the number we just need to return the difference between the amount of I's

Isaac
  • 11,409
  • 5
  • 33
  • 45
  • Thanks Issac, I'm new to RegEx, read up on some brief documentation. I get the matching call you did, but could you explain the if/else statement? That part is hard to grasp! – Kode_12 Jul 27 '16 at 03:19
  • @Kode_12 I updated the if statements and added an explanation – Isaac Jul 27 '16 at 03:44
0

Use sort with a comparator.

// assume we want to have arbitrary roman numerals - we should have some form of lookup
var numeralLookup = {
  I: 1,
  II: 2,
  III: 3,
  IV: 4
} //etc

// helper function - parse Roman Numeral from your string
function getNumeral(str) {
  return str.split()[1]
}

// helper function - parse number after '#' from your string
function getNumber(str) {
  return parseInt(str.slice(str.indexOf('#') + 1))
}

// sort
arr.sort(function(a, b) {
  var aNum = numeralLookup[getNumeral(a.myLevel)];
  var bNum = numeralLookup[getNumeral(b.myLevel)];

  return aNum === bNum ? getNumber(a.myLevel) - getNumber(b.myLevel) : aNum - bNum;
})
Damon
  • 4,216
  • 2
  • 17
  • 27
0

Believe it or not a faster alternative to Array.sort is Underscore's sortBy function. Check out their documentation here. The library has all sorts of great utilities for doing stuff like this.

var stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}];
_.sortBy(stooges, 'name');
=> [{name: 'curly', age: 60}, {name: 'larry', age: 50}, {name: 'moe', age: 40}];
Patrick Motard
  • 2,650
  • 2
  • 14
  • 23
  • This doesn't answer the question. The OP isn't (yet) worried about speed, because they don't know how to achieve the correct sort order in the first place. – nnnnnn Jul 27 '16 at 01:04
  • This absolutely answers his question. He didn't ask how to do it from scratch. He asked how to do it. This is one way to do it. :) – Patrick Motard Jul 27 '16 at 01:06
  • It's not a plain string sort, or a plain numeric sort. The OP's values include string and numeric data with two different numbers (one in Roman numerals) *in the same property*. Your answer doesn't even mention that. So no, it doesn't answer the question. – nnnnnn Jul 27 '16 at 01:09
  • Meh, the docs make it clear that a function can be handed to it to determine order. You could say i left that to the reader. ;) This is all just a giant pissing contest anyways. His question has been asked a million times and should be flagged as duplicate. – Patrick Motard Jul 27 '16 at 01:11
  • I was about to close it as a duplicate, until I noticed that he needed a sub sort within the same field, and I couldn't find a duplicate for that. – nnnnnn Jul 27 '16 at 01:24
  • did you find the answer to sort array ? – mohsen Ghalandar Mar 11 '22 at 08:35