4

Say I have an array like this:

let arr = ["1.2.5", "1", "10", "2.0.4", "3.3.3.3"];

What would be the best way to sort this and get result like this:
let arr = ["1", "1.2.5", "2.0.4", "3.3.3.3", "10"];

First I thought of converting each item in the array into 'float' may work but then multiple decimals won't give expected results.

I can also go for a for loop and doing stuff like item.split(".") and then check one by one, but I do not think this is the best way.

Any suggestions, please?

5
  • is 3.3.3.3 a number? no right? Commented Jul 17, 2017 at 6:44
  • yeah i know but what i don't know what else i call it to explain what result i expect. However i do hope you get my point here. Commented Jul 17, 2017 at 6:45
  • 2.0.4 is not a number just like others, and hence it can't be sorted like numericals. Commented Jul 17, 2017 at 6:48
  • ok, what i want is not 'sort like numbers' but just sorting. Please let me know if i can rewrite my question in a better for explanation. Commented Jul 17, 2017 at 6:50
  • You can try sorting by first number. arr.sort(function(a,b){ return a.split('.')[0] - b.split('.')[0]; }); Commented Jul 17, 2017 at 6:52

5 Answers 5

7

You could use String#localeCompare with options

sensitivity

Which differences in the strings should lead to non-zero result values. Possible values are:

  • "base": Only strings that differ in base letters compare as unequal. Examples: a ≠ b, a = á, a = A.
  • "accent": Only strings that differ in base letters or accents and other diacritic marks compare as unequal. Examples: a ≠ b, a ≠ á, a = A.
  • "case": Only strings that differ in base letters or case compare as unequal. Examples: a ≠ b, a = á, a ≠ A.
  • "variant": Strings that differ in base letters, accents and other diacritic marks, or case compare as unequal. Other differences may also be taken into consideration. Examples: a ≠ b, a ≠ á, a ≠ A.

The default is "variant" for usage "sort"; it's locale dependent for usage "search".

numeric

Whether numeric collation should be used, such that "1" < "2" < "10". Possible values are true and false; the default is false. This option can be set through an options property or through a Unicode extension key; if both are provided, the options property takes precedence. Implementations are not required to support this property.

var array = ["1.2.5", "1", "10", "2.0.4", "3.3.3.3"];

array.sort(function (a,b) {
    return a.localeCompare(b, undefined, { numeric: true, sensitivity: 'base' });
});

console.log(array);

Sign up to request clarification or add additional context in comments.

Comments

4
function compare(a, b) {
    var aSplit = a.split(".");
    var bSplit = b.split(".");


    var length = Math.min(aSplit.length, bSplit.length);
    for (var i = 0; i < length; ++i) {
        if (parseInt(aSplit[i]) < parseInt(bSplit[i])) {
            return -1;
        } else if (parseInt(aSplit[i]) > parseInt(bSplit[i])) {
            return 1;
        }
    }

    if (aSplit.length < bSplit.length) {
        return -1;
    } else if (aSplit.length > bSplit.length) {
        return 1;
    }

    return 0;
}

You can use it like: arr.sort((a, b) => compare(a, b));

Comments

1

Here is my solution (uses ES6 syntax)

const arr = ["1.2.5", "1", "10", "2.0.4", "3.3.3.3"];

const result = arr
.map((n) => n.split('.').map((c) => c.padStart(10, '0')).join('.'))
.sort()
.map((n) => n.split('.').map((c) => +c).join('.'))

console.log(result);

3 Comments

can you please explain this a little bit
the 1st map() adds leading zeros, i.e it does the following conversion "1.2.3" => "0000000001.0000000002.0000000003" and after that sorting works correctly. The 2nd map() just removes leading zeros.
well that's a nice way to do it, thanks for explaining. I didn't knew about padStart
0

var arr = ["1.2.5", "1", "10", "2.0.4", "3.3.3.3"];

var arr = ["1.2.5", "1", "10", "2.0.4", "3.3.3.3"];
console.log(arr.sort(function(a,b){

  var arr1 = a.split('.');
  var arr2 = b.split('.');
  
  var maxlen = Math.max(arr1.length,arr2.length);
  
  var i;

  for(i = 0;i<maxlen;i++){
  		var i1 = parseInt(arr1[i] || 0)
      var i2 = parseInt(arr2[i] || 0)
			if(i1 < i2){
      			return -1;
      }
      else if(i1 > i2){
      			return 1;
      }
  }
  
  return 0;

}));

Comments

-1
  • sort 1.0a notation correct
  • use native localeCompare to sort 1.090 notation

function log(label,val){
  document.body.append(label,String(val).replace(/,/g," - "),document.createElement("BR"));
}

const sortVersions = (
  x,
  v = s => s.match(/[a-z]|\d+/g).map(c => c==~~c ? String.fromCharCode(97 + c) : c)
) => x.sort((a, b) => (a + b).match(/[a-z]/) 
                             ? v(b) < v(a) ? 1 : -1 
                             : a.localeCompare(b, 0, {numeric: true}))

let v=["1.90.1","1.090","1.0a","1.0.1","1.0.0a","1.0.0b","1.0.0.1","1.0a"];
log(' input : ',v);
log('sorted: ',sortVersions(v));
log('no dups:',[...new Set(sortVersions(v))]);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.