13

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;
    });
}
6
  • why don't you return 1 in the first if of both sorts when checking empty strings? Doesn't that do the trick? Commented Nov 24, 2011 at 11:25
  • @RobertKoritnik I did try that and the bank values ended up in between other values 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. 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? Commented Nov 24, 2011 at 11:43
  • And do you really want to sort numbers (even if they are stored in strings) like this? Commented Nov 24, 2011 at 11:45

4 Answers 4

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())
    });
}
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks a lot That does exactly what I would like!
Hmm... I have now noticed though that this does not behave the same in all browsers
Columns with "0" and "" in them throw it off
@ChrisJ: is that zero a number or a string with zero? And what about the second one? Is that a string with two double quotes or empty string, null or anything else? Empty strings work. It is true that numerical zero wouldn't work. But you didn't say which types you're having in your arrays. But all of these can still be solved without too much complications. If you're using other types as well, then toUpperCase can't work without type conversion in the first place.
They're always strings. I'm updating my question to be more specific about the possible values
|
1

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

1 Comment

I tried this: if (a[colToSortBy] == '' || b[colToSortBy] == '') return-1; in each sort method but it still didn't work
0

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

Comments

0

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>

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.