Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

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'}
   ] 
share|improve this question
    
A similar question to this has already been asked: stackoverflow.com/questions/1129216/… – Richard Chassereau Jul 27 at 0: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 at 1:06
    
nope, it's capped at III, that would be painful – Kode_12 Jul 27 at 1:12
    
If those are Roman numbers, then this will need a roman number parser to get true roman numeral order. Yuck. – jfriend00 Jul 27 at 1:19
up vote 1 down vote accepted

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

share|improve this answer
    
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 at 3:19
    
@Kode_12 I updated the if statements and added an explanation – Isaac Jul 27 at 3:44

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.

share|improve this answer
    
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 at 2:31

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}];
share|improve this answer
    
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 at 1: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 at 1: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 at 1: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 at 1: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 at 1:24

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;
})
share|improve this answer
    
You need to include the "CAT x" part in the sort criteria too. – nnnnnn Jul 27 at 1:04
    
@nnnnnn good point totally missed that : ) – Damon Jul 27 at 1:05

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.