简体   繁体   中英

How to sort an array with null values

There are quite a few question related to the topic, but I couldn't find the right solution for my case.

var arr = [a, b, null, d, null]

and am sorting this Array with below logic

return function(a,b){ 

    if(a === null){
      return 1;
    }
    else if(b === null){
      return -1;
    }
    else if(a === b){
      return 0;
    }
    else if(ascending) {
      return a < b ? -1 : 1;
    }
    else if(!ascending) {
      return a < b ? 1 : -1;
    }
  };

I get the following outputs for

Ascending : [a, b,  d, null,null]

Descending : [d, b,  a, null,null]

Expected : [null, null,d, b,  a]

What am I doing wrong?

 function getSort (ascending) { // if ascending, `null` will be pushed towards the end of the array by returning 1 var nullPosition = ascending ? 1 : -1 return function (a, b) { // if a is null, push it towards whichever end null elements should end up if (a == null) return nullPosition // Note: at this point, a is non-null (previous if statement handled that case). // // If b is null, it must therefore be placed closer to whichever end the null // elements should end up on. If ascending, null elements are pulled towards // the right end of the array. If descending, null elements are pulled towards // the left. // // Therefore, we return -nullPosition. If ascending, this is -1, meaning a comes // before b; if descending, this is 1, meaning a comes after b. This is // clearly the correct behavior, since ascending will push b, which is null, // towards the end of the array (with -1) and descending will push b towards // the beginning of the array. if (b == null) return -nullPosition // OTHERWISE, both elements are non-null, so sort normally. // if a < b AND // if ascending, a comes first, so return -1 == -nullPosition // if descending, a comes after, so return -nullPosition == -(-1) == 1 if (a < b) return -nullPosition // return the opposite of the previous condition if (a > b) return nullPosition // return 0 if both elements are equal return 0 } } function write (arr) { arr.forEach(function (d) { document.write(d + "<br>")})} var toSort = ['a', 'b', null, 'd', null] var sortA = getSort(true) var sortD = getSort(false) document.write("<br>ASCENDING<br>") write(toSort.sort(sortA)) document.write("<br>DESCENDING<br>") write(toSort.sort(sortD)) 

You could use a two pass approach by checking null values first and then order by string.

To change the sort order, you could swap the parameters or use a negated result of the one of the function.

 var data = ['a', 'b', null, 'd', null]; // ascending data.sort(function (a, b) { return (a === null) - (b === null) || ('' + a).localeCompare(b); }); console.log(data); // descending data.sort(function (a, b) { return (b === null) - (a === null) || ('' + b).localeCompare(a); }); console.log(data); 
 .as-console-wrapper { max-height: 100% !important; top: 0; } 

What about the below solution?

var arr = [null, 'e', 'a', 'b', null, 'd', null];

function sortBy(arr, ascending) {
    return arr.sort((a, b) => {
        if(!a) return ascending ? 1 : -1;
        if(!b) return ascending ? -1 : 1;
        if (ascending) return a > b ? 1 : -1;
        return a > b ? -1 : 1;
    })
}

const ascendingArr = sortBy(arr, true);
console.log(ascendingArr);
const decendingArr = sortBy(arr, false);
console.log(decendingArr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM