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

sorting - Sort javascript array so that blank values are always at bottom - Stack Overflow

programmeradmin0浏览0评论

So I have an array of arrays which contain only strings. The array of arrays is to be displayed as a table and may have over 1000 rows with 20 or more values in each.

eg:

var arr = [
    ["bob","12","yes"],
    ["joe","","no"],
    ["tim","19","no"],
    ["dan","","yes"],
    ["tim","",""],
    ["dan","0",""]
]

the strings may contain anything that can be represented as a string, including: " ", "", "0" or "00-00-00" etc... and any column my be used for ordering.

I am sorting the arrays ascending and descending but some of the values I am sorting by are blank strings: "". How could I get the blank strings (only) to always be at the end of the new arrays in all modern browsers?

currently they are at the end when ascending but at the start when descending.

I am sorting like below (Yes I'm sure I can do it shorter too):

if (direction == "asc") {
    SortedArr = arr.sort(function (a, b) {
        if (a[colToSortBy] == '') {
            return -1;
        }
        if (a[colToSortBy].toUpperCase() < b[colToSortBy].toUpperCase()) {
            return -1;
        }
        if (a[colToSortBy].toUpperCase() > b[colToSortBy].toUpperCase()) {
            return 1;
        }
        return 0;
    });
} else {
    SortedArr = arr.sort(function (a, b) {
        if (a[colToSortBy] == '') {
            return -1;
        }
        if (b[colToSortBy].toUpperCase() < a[colToSortBy].toUpperCase()) {
            return -1;
        }
        if (b[colToSortBy].toUpperCase() > a[colToSortBy].toUpperCase()) {
            return 1;
        }
        return 0;
    });
}

So I have an array of arrays which contain only strings. The array of arrays is to be displayed as a table and may have over 1000 rows with 20 or more values in each.

eg:

var arr = [
    ["bob","12","yes"],
    ["joe","","no"],
    ["tim","19","no"],
    ["dan","","yes"],
    ["tim","",""],
    ["dan","0",""]
]

the strings may contain anything that can be represented as a string, including: " ", "", "0" or "00-00-00" etc... and any column my be used for ordering.

I am sorting the arrays ascending and descending but some of the values I am sorting by are blank strings: "". How could I get the blank strings (only) to always be at the end of the new arrays in all modern browsers?

currently they are at the end when ascending but at the start when descending.

I am sorting like below (Yes I'm sure I can do it shorter too):

if (direction == "asc") {
    SortedArr = arr.sort(function (a, b) {
        if (a[colToSortBy] == '') {
            return -1;
        }
        if (a[colToSortBy].toUpperCase() < b[colToSortBy].toUpperCase()) {
            return -1;
        }
        if (a[colToSortBy].toUpperCase() > b[colToSortBy].toUpperCase()) {
            return 1;
        }
        return 0;
    });
} else {
    SortedArr = arr.sort(function (a, b) {
        if (a[colToSortBy] == '') {
            return -1;
        }
        if (b[colToSortBy].toUpperCase() < a[colToSortBy].toUpperCase()) {
            return -1;
        }
        if (b[colToSortBy].toUpperCase() > a[colToSortBy].toUpperCase()) {
            return 1;
        }
        return 0;
    });
}
Share Improve this question edited Nov 24, 2011 at 20:55 Chris J asked Nov 24, 2011 at 11:18 Chris JChris J 8431 gold badge9 silver badges16 bronze badges 6
  • why don't you return 1 in the first if of both sorts when checking empty strings? Doesn't that do the trick? – Robert Koritnik Commented Nov 24, 2011 at 11:25
  • @RobertKoritnik I did try that and the bank values ended up in between other values – Chris J Commented Nov 24, 2011 at 11:28
  • I've just tried your sample data and sorted on the second column (which has empty strings) and changing return -1 to return 1 in ifs checking empty strings and they indeed got to the end. You've probably sorted some other column to get them in the middle. The first column (array index 0 since index is zero based) seems to do just that. – Robert Koritnik Commented Nov 24, 2011 at 11:35
  • @Robert Koritnik I tried the same thing but didn't get your result. When I change the -1 into 1, it just "swaps" the 2 first lines. Chris, you want the lines with empty value at the end, only when the sorting column is the 2nd one, right? – Rodolphe Commented Nov 24, 2011 at 11:43
  • And do you really want to sort numbers (even if they are stored in strings) like this? – Rodolphe Commented Nov 24, 2011 at 11:45
 |  Show 1 more comment

4 Answers 4

Reset to default 8

Empty strings at the end

Working example on JSFiddle that puts empty strings always at the end no matter whether order is ascending or descending. This may be a usability issue, but this is the solution:

if (direction == "asc") {
    SortedArr = arr.sort(function (a, b) {
        return (a[col] || "").toUpperCase().localeCompare((b[col] || "").toUpperCase())
    });
} else {
    SortedArr = arr.sort(function (a, b) {
        return (b[col] || "!!!").toUpperCase().localeCompare((a[col] || "!!!").toUpperCase())
    });
}

I think your problem comes from the fact that you're checking if a[colToSortBy] is an emtpy string but you don't do it for b[colToSortBy].

I am writing an application that must work on IE, FF, Safari, Chrome, Opera, Desktop, Tablet (including iPad) & phones (including iPhone). This means I keep testing across browsers. I thus discovered that my sort procedure below wasn't working correctly in FF until I added the 'new section' part of the code. Reason being I did not take care of sorting when a numeric value is not supplied (dash, -). FF was also not working correctly with negative (-) values. This code now works perfectly across:

if (SortByID == 0) {                //string values (Bank Name)
    myValues.sort( function (a,b) {
        var nameA = a[SortByID].toUpperCase(), nameB = b[SortByID].toUpperCase();
        if (SortOrderID == 1) {         //sort string ascending
            if (nameA < nameB) { return -1; } else { if (nameA > nameB) { return 1; } }
        } else {                        //sort string descending
            if (nameA < nameB) { return 1; } else { if (nameA > nameB) { return -1; } }
        }
        return 0                    //default return value (no sorting)
    })
} else {                            //numeric values (Items)
    myValues.sort(function (a, b) {
        if (isNumber(a[SortByID]) && isNumber(b[SortByID])) { //
            if (SortOrderID == 1) { //sort number ascending
                return parseFloat(a[SortByID]) - parseFloat(b[SortByID]);
            } else {                //sort string descending
                return parseFloat(b[SortByID]) - parseFloat(a[SortByID]);
            }
        } else { //one of the values is not numeric
            //new section
            if (!isNumber(a[SortByID])) {
                if (SortOrderID == 1) { //sort number ascending
                    return -1;
                } else {                //sort number descending
                    return 1;
                }
            } else {
                if (!isNumber(b[SortByID])) {
                    if (SortOrderID == 1) { //sort number ascending
                        return 1;
                    } else {                //sort number descending
                        return -1;
                    }
                }
            }//New section
            return 0;
        }
    })
}

I know it is long, but it is simple enough for me to understand. I hope it also addresses the browser issue raised by Chris J. *isNumber is a simple function testing if value !isNAN

I used this way in my app...

You can tweak it to get the favorable result. we also have the Number.MAX_SAFE_INTEGER

var arr = [10, "", 8, "", 89, 72]

var min = Number.MIN_SAFE_INTEGER

var sorted = arr.sort(function (a,b) {
  return (a || min) - (b || min)
})

var cons = document.getElementById("console")

cons.innerText = "Ascending " + JSON.stringify(sorted) + "\n" + "Descending " +  JSON.stringify(sorted.reverse())
<html>
  <head></head>
  <body>
    <p id="console"></p>
  </body>
</html>

发布评论

评论列表(0)

  1. 暂无评论