13

I've got a bunch of "numbers" that have multiple decimal points (so they're really strings). However, I want to sort them as if they were numbers.

1.1.1
10.2.3
2.6.7
21.10.4
3.10.12
4.11.5
4.1.16
6.4.23

I want them to sort by the first set of numbers (before the first decimal point), then by the second set, then by the third (with the possibility of it continuing for a fourth set or more). They should go in this order:

1.1.1
2.6.7
3.10.12
4.1.16
4.11.5
6.4.23
10.2.3
21.10.4

What is the best way to do this using JS? I'm thinking I'll probably need to break each number into an array, but there maybe a better way. Ideas?

Huangism
  • 16,278
  • 7
  • 48
  • 74
thugsb
  • 22,856
  • 6
  • 30
  • 44
  • 1
    Splitting each number into an array and the ordering each set, while keeping track of each string in association to it's split array.. Could get interesting. [1](http://stackoverflow.com/a/1063027/1257652) [2](http://stackoverflow.com/a/1063027/1257652) – Brett Weber Nov 19 '13 at 19:37
  • Updated to handle any number of dots : http://stackoverflow.com/a/20080885/1636522 –  Nov 20 '13 at 06:19

4 Answers4

14

I think something like this should do the trick:

nums.sort(function(a, b) {
    var nums1 = a.split(".");
    var nums2 = b.split(".");

    for (var i = 0; i < nums1.length; i++) {
        if (nums2[i]) { // assuming 5..2 is invalid
            if (nums1[i] !== nums2[i]) {
               return nums1[i] - nums2[i];   
            } // else continue
        } else {
            return 1; // no second number in b
        }
    }
    return -1; // was missing case b.len > a.len
});

Update heres a fiddle

When var nums = ['1.1.1', '2.6.7.3.2', '2.6.7', '2.6.7.3', '2.6.7.1', '6.4.23', '2.7']

Sorting this way => ['1.1.1','2.6.7.1','2.6.7.3.2','2.6.7','2.6.7.3','2.7','6.4.23']

megawac
  • 10,953
  • 5
  • 40
  • 61
5

To please megawac :D

list.sort(function (a, b) {
    var result;
    a = a.split('.');
    b = b.split('.');
    while (a.length) {
        if (result = a.shift() - (b.shift() || 0)) {
            return result;
        }
    }
    return -b.length;
});

Handles any number of dots :

input  ['1.3', '10', '1.2', '2', '1.1.2', '1.1.1', '1.1']
output ['1.1', '1.1.1', '1.1.2', '1.2', '1.3', '2', '10']
2

Try this :

var list = ['1.1.1', '10.2.3', '2.6.7', '21.10.4', '3.10.12', '4.11.5', '4.1.16', '6.4.23'];

list.sort(function (a, b) {
    a = a.split('.');
    b = b.split('.');
    return (
        a.shift() - b.shift()
    ) || (
        a.shift() - b.shift()
    ) || (
        a.shift() - b.shift()
    );
});
  • 1
    If you use a `while` loop to shift here you can handle `n` amount of decimals – megawac Nov 19 '13 at 19:49
  • @megawac I know, I'm just too lazy to create a variable to deal with the result of the substraction :D –  Nov 19 '13 at 19:50
0

I went about this by splitting each number into an array and then performing a multidimensional sort, using a custom sort method. Here's what I've got:

function multiDecimalSort(input) {
    var output,
        i,
        len;

    output = [];

    // Unglue decimal parts
    for (i = 0, len = input.length; i < len; i++) {
        output.push(input[i].split('.'));
    }

    // Apply custom sort
    output.sort(function (a, b) {
        for (i = 0, len = a.length; i < len; i++) {
            // cast decimal part to int
            a[i] = parseInt(a[i], 10);
            b[i] = parseInt(b[i], 10);

            if (a[i] !== b[i]) {
                return a[i] - b[i];
            }
        }
    });

    // Rejoin decimal parts
    for (i = 0, len = input.length; i < len; i++) {
        output[i] = output[i].join(".");
    }

    return output;
}
pgoldrbx
  • 31
  • 3