最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can one compare string and numeric values (respecting negative values, with null always last)? - Stack Overflow

programmeradmin1浏览0评论

I'm trying to sort an array of values that can be a mixture of numeric or string values (e.g. [10,"20",null,"1","bar","-2",-3,null,5,"foo"]). How can I sort this array such that

  • null values are always placed last (regardless of sorting order, see jsFiddle)
  • negative numbers are sorted correctly (i.e. they are less than positive numbers and sort correctly amongst themselves)

? I made a jsFiddle with detailed numeric and string examples (using localeCompare and the numeric option), but will paste the numeric version of my sorting algorithm below as a starting point.

// Sorting order
var order = "asc"; // Try switching between "asc" and "dsc"

// Dummy arrays
var numericArr = [10,20,null,1,-2,-3,null,5];

// Sort arrays
$(".output1").append(numericArr.toString());
numericArr.sort(sortByDataNumeric);
$(".output2").append(numericArr.toString());

// Numeric sorting function
function sortByDataNumeric(a, b, _order) {

    // Replace internal parameters if not used
    if (_order == null) _order = order;

    // If values are null, place them at the end
    var dflt = (_order == "asc" ? Number.MAX_VALUE : -Number.MAX_VALUE);

    // Numeric values
    var aVal = (a == null ? dflt : a);
    var bVal = (b == null ? dflt : b);
    return _order == "asc" ? (aVal - bVal) : (bVal - aVal);
}

The problem with my string sorting algorithm (see jsFiddle) is that I can't find a way to always place null values last and negative values aren't correctly sorted within themselves (e.g. -3 should be less than -2)

Edit

To answer the comments, I expect [10,"20",null,"1","bar","-2",-3,null,5,"foo"] to sort to [-3,"-2","1",5,10,"20","bar","foo",null,null]

I'm trying to sort an array of values that can be a mixture of numeric or string values (e.g. [10,"20",null,"1","bar","-2",-3,null,5,"foo"]). How can I sort this array such that

  • null values are always placed last (regardless of sorting order, see jsFiddle)
  • negative numbers are sorted correctly (i.e. they are less than positive numbers and sort correctly amongst themselves)

? I made a jsFiddle with detailed numeric and string examples (using localeCompare and the numeric option), but will paste the numeric version of my sorting algorithm below as a starting point.

// Sorting order
var order = "asc"; // Try switching between "asc" and "dsc"

// Dummy arrays
var numericArr = [10,20,null,1,-2,-3,null,5];

// Sort arrays
$(".output1").append(numericArr.toString());
numericArr.sort(sortByDataNumeric);
$(".output2").append(numericArr.toString());

// Numeric sorting function
function sortByDataNumeric(a, b, _order) {

    // Replace internal parameters if not used
    if (_order == null) _order = order;

    // If values are null, place them at the end
    var dflt = (_order == "asc" ? Number.MAX_VALUE : -Number.MAX_VALUE);

    // Numeric values
    var aVal = (a == null ? dflt : a);
    var bVal = (b == null ? dflt : b);
    return _order == "asc" ? (aVal - bVal) : (bVal - aVal);
}

The problem with my string sorting algorithm (see jsFiddle) is that I can't find a way to always place null values last and negative values aren't correctly sorted within themselves (e.g. -3 should be less than -2)

Edit

To answer the comments, I expect [10,"20",null,"1","bar","-2",-3,null,5,"foo"] to sort to [-3,"-2","1",5,10,"20","bar","foo",null,null]

Share Improve this question edited Sep 30, 2013 at 19:10 lebolo asked Sep 30, 2013 at 18:49 lebololebolo 2,1504 gold badges30 silver badges47 bronze badges 11
  • 1 What should happen to "bar"? It's neither a number, a numeric string nor null. – Bergi Commented Sep 30, 2013 at 18:53
  • 1 and should "20" (string) sort before or after 20 (integer)? Or after all numeric values? – andi Commented Sep 30, 2013 at 18:55
  • Are you referring to the alpha sort, rather than the code you show? Alpha order isn't the same as numeric order, and you shouldn't be surprised at the order shown. – Dave Newton Commented Sep 30, 2013 at 18:56
  • 1 How do you want to sort the strings? Relevant example: ["-1", 3, "10", "foo"] – Tibos Commented Sep 30, 2013 at 19:01
  • @Bergi Added the expected answer, thanks. – lebolo Commented Sep 30, 2013 at 19:23
 |  Show 6 more comments

4 Answers 4

Reset to default 11

You should first check to see if either value is null and return the opposite value.


On a side note:

For your default _order value, you should check if the parameter is undefined instead of comparing its value to null. If you try to compare something that is undefined directly you will get a reference error:

(undefinedVar == null) // ReferenceError: undefinedVar is not defined

Instead, you should check if the variable is undefined:

(typeof undefinedVar == "undefined") // true

Also, it's probably a better idea to wrap your compare function in a closure instead of relying on a global order variable.

Sometime like:

[].sort(function(a, b){ return sort(a, b, order)})

This way you can sort at a per-instance level.


http://jsfiddle.net/gxFGN/10/

JavaScript

function sort(a, b, asc) {
    var result;

    /* Default ascending order */
    if (typeof asc == "undefined") asc = true;

    if (a === null) return 1;
    if (b === null) return -1;
    if (a === null && b === null) return 0;

    result = a - b;

    if (isNaN(result)) {
        return (asc) ? a.toString().localeCompare(b) : b.toString().localeCompare(a);
    }
    else {
        return (asc) ? result : -result;
    }
}
function sortByDataString(a, b) {
    if (a === null) {
        return 1;
    }
    if (b === null) {
        return -1;
    }
    if (isNumber(a) && isNumber(b)) {
        if (parseInt(a,10) === parseInt(b,10)) {
            return 0;
        }
        return parseInt(a,10) > parseInt(b,10) ? 1 : -1;
    }
    if (isNumber(a)) {
        return -1;
    }
    if (isNumber(b)) {
        return 1;
    }
    if (a === b) {
        return 0;
    }
    return a > b ? 1 : -1;
}

fiddle here: http://jsfiddle.net/gxFGN/6/

I left out the order parameter, but you could always reverse the array at the end if needed.

Use this:

function typeOrder(x) {
    if (x == null)
        return 2;
    if (isNaN(+x))
        return 1;
    return 0;
}
function sortNumber(a, b) {
    a = parseInt(a, 10); b = parseInt(b, 10);
    if (isNaN(a) || isNaN(b))
        return 0;
    return a - b;
}
function sortString(a, b) {
    if (typeof a != "string" || typeof b != "string")
       return 0;
    return +(a > b) || -(b > a);
}

order = order == "dsc" ? -1 : 1;
numericArr.sort(function(a, b) {
    return order * ( typeOrder(a)-typeOrder(b)
                     || sortNumber(a, b)
                     || sortString(a, b)
                   );
});

(updated fiddle)

I'm pretty sure that your problem is a red herring... the abstract function that you past into sort doesn't get a third parameter (in your case _order). So in your situation that's always going to be undefined.

Please reconsider your code with that in mind and see what you get.

The array you specify is entirely Numeric so your sort should work correctly, though as other commenters have suggested, if your array ever winds up with string values (i.e. "10", "-7" etc) you'll want to parseInt and test for isNaN before doing your comparison.

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论