Chris J
Chris J

Reputation: 843

Sort javascript array so that blank values are always at bottom

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;
    });
}

Upvotes: 13

Views: 9677

Answers (4)

Vikas Gautam
Vikas Gautam

Reputation: 1913

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>

Upvotes: 0

Hannington Mambo
Hannington Mambo

Reputation: 1090

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

Upvotes: 0

Robert Koritnik
Robert Koritnik

Reputation: 105029

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())
    });
}

Upvotes: 8

Rodolphe
Rodolphe

Reputation: 1731

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].

Upvotes: 1

Related Questions