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

4 Answers 4

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

2
  • 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
    CommentedJul 27, 2016 at 3:19
  • @Kode_12 I updated the if statements and added an explanation
    – Isaac
    CommentedJul 27, 2016 at 3:44
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.

1
  • 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).CommentedJul 27, 2016 at 2:31
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}]; 
6
  • 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
    CommentedJul 27, 2016 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. :)CommentedJul 27, 2016 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
    CommentedJul 27, 2016 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.CommentedJul 27, 2016 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
    CommentedJul 27, 2016 at 1:24
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; }) 
1
  • You need to include the "CAT x" part in the sort criteria too.
    – nnnnnn
    CommentedJul 27, 2016 at 1:04

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.