2

I am developing an application using Reactjs and underscore.js . I am trying to sort a list using name which is a string. However, the names contains numbers, as a result the sorting is not right. Here is an example of my code and its result:

items= _.sortBy(items, function (item) {
    return item.name.toLowerCase()
});

Result:

S1.2M (FA)
S10.1M
S10.2M
S10.4M
S11 (GR14)
S2 (DT)
S3.1M (GR17)

but I want the result, to be like this :

S1.2M (FA)
S2 (DT)
S3.1M (GR17)
S10.1M
S10.2M
S10.4M
S11 (GR14)

how can I achieve this?

Rob
  • 14,746
  • 28
  • 47
  • 65
user261002
  • 2,182
  • 10
  • 46
  • 73

2 Answers2

2

Short answer: The term you are looking for is 'Natural Sort' and it is not something you can easily achieve in 1 line.

Underscore makes it even harder because it doesn't provide you 2 elements to compare, but just 1 to provide a measure to compare on.

You can find plenty of examples:

Javascript : natural sort of alphanumerical strings

and

Underscore.js sort an array of objects alphanumerically

The closest you can achieve with underscorejs is something like:

_.sortBy(items, function (a) {
    return parseInt(a.match(/\d+/)[0]);
});

which simply compares the 1st number (not digit) in the string.

Community
  • 1
  • 1
SDekov
  • 9,276
  • 1
  • 20
  • 50
2

It can by done by using sortBy() twice.

    var items = [
          {"name":"S1.2M (FA)"},
          {"name":"S10.1M"},
          {"name":"S10.2M"},
          {"name":"S10.4M"},
          {"name":"S11 (GR14)"},
          {"name":"S2 (DT)"},
          {"name":"S3.1M (GR17)"}
        ]
        
        //sort by alphabetical order
        items = _.sortBy(items, function (item) {
            return item.name.toLowerCase()
        })

        //sort while ignoring first character
        items = _.sortBy(items, function(item) {
         return item.name.substring(1);
        });


_.each(items, function(item) {
  $('ul').append('<li>'+item.name+'</li>')
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/underscorejs/1.8.3/underscore-min.js"></script>

<ul></ul>

I'm sure this can be written in a cleaner way. I'll try and edit it later if I have time, but this should work.

Gene Parcellano
  • 5,799
  • 5
  • 36
  • 43
  • 1
    Nice trick, but it doesn't work for two reasons. Firstly, sorting by substring(1) is still alphabetic instead of numeric. Secondly, the final sort completely overrides the order except for equal elements. The relative order within a group of equal elements is preserved from the previous sort. The final sort should be by the first letter, and to have e.g. the S's sorted by number you should sort by the numeric part _beforehand_. It's important to sort by _just_ the first letter in the final sort so that all the S's will be considered equal and have their relative order preserved. – tom Jul 12 '16 at 18:02