Sort an array so that null values always come last

Javascript

Javascript Problem Overview


I need to sort an array of strings, but I need it so that null is always last. For example, the array:

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

When sorted ascending I need it to be sorted like [a, b, d, null, null] and when sorted descending I need it to be sorted like [d, b, a, null, null].

Is this possible? I tried the solution found below but it's not quite what I need.

https://stackoverflow.com/questions/19101573/how-can-one-compare-string-and-numeric-values-respecting-negative-values-with

Javascript Solutions


Solution 1 - Javascript

Check out .sort() and do it with custom sorting. Example

function alphabetically(ascending) {

  return function (a, b) {

    // equal items sort equally
    if (a === b) {
        return 0;
    }
    // nulls sort after anything else
    else if (a === null) {
        return 1;
    }
    else if (b === null) {
        return -1;
    }
    // otherwise, if we're ascending, lowest sorts first
    else if (ascending) {
        return a < b ? -1 : 1;
    }
    // if descending, highest sorts first
    else { 
        return a < b ? 1 : -1;
    }

  };

}

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

console.log(arr.sort(alphabetically(true)));
console.log(arr.sort(alphabetically(false)));

Solution 2 - Javascript

Use a custom compare function that discriminates against null values:

arr.sort(function(a, b) {
    return (a===null)-(b===null) || +(a>b)||-(a<b);
});

For descending order of the non-null values, just swap a and b in the direct comparison:

arr.sort(function(a, b) {
    return (a===null)-(b===null) || -(a>b)||+(a<b);
});

Solution 3 - Javascript

Ascending

arr.sort((a, b) => (a != null ? a : Infinity) - (b != null ? b : Infinity))

Descending

arr.sort((a, b) => (b != null ? b : -Infinity) - (a != null ? a : -Infinity))

(For descending order if you don't have negative values in the array, I recommend to use 0 instead of -Infinity)

Solution 4 - Javascript

The simplest approach is to handle null first, then deal with non-null cases based on the desired order:

function sortnull(arr, ascending) {
  // default to ascending
  if (typeof(ascending) === "undefined")
    ascending = true;

  const multiplier = ascending ? 1 : -1;

  const sorter = function(a, b) {
    if (a === b)          // identical? return 0
      return 0;
    else if (a === null)  // a is null? last 
      return 1;
    else if (b === null)  // b is null? last
      return -1;
    else                  // compare, negate if descending
      return a.localeCompare(b) * multiplier;
  }

  return arr.sort(sorter);
}

const arr = ["a", "b", null, "d", null];

console.log(sortnull(arr));        // ascending   ["a", "b", "d", null, null]
console.log(sortnull(arr, true));  // ascending   ["a", "b", "d", null, null]
console.log(sortnull(arr, false)); // descending  ["d", "b", "a", null, null]

Solution 5 - Javascript

If you need natural sorting for numbers, or any of the options provided by Collator (including speed enhancements and respecting locale), try this approach, based off of Paul Roub's solution, cleaned up a bit. We almost always use numeric sorting, hence the defaults...

If you are not a Typescript fan, just strip off the :type specs or copy from the snippet.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

const naturalCollator = new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'});
const alphabeticCollator = new Intl.Collator(undefined, {});

function nullSort(descending: boolean = false, alphabetic: boolean = false) {
  return function (a: any, b: any): number {
    if (a === b) {
      return 0;
    }
    if (a === null) {
      return 1;
    }
    if (b === null) {
      return -1;
    }

    let ret
    if (alphabetic) {
      ret = alphabeticCollator.compare(a, b)
    } else {
      ret = naturalCollator.compare(a, b)
    }
    if (descending) {
      ret = -ret
    }
    return ret
  };
}

Use it like this.

// numeric, ascending (default)
myList.sort(nullSort());

// alphabetic, descending
myList.sort(nullSort(true, true));

You can modify the factory method to take a collator instead, for greater flexibility.

function nullSort(descending: boolean = false, collator: Collator = naturalCollator)

Working Snippet

const naturalCollator = new Intl.Collator(undefined, {
  numeric: true,
  sensitivity: 'base'
});
const alphabeticCollator = new Intl.Collator(undefined, {});

function nullSort(descending = false, alphabetic = false) {
  return function(a, b) {
    if (a === b) {
      return 0;
    }
    if (a === null) {
      return 1;
    }
    if (b === null) {
      return -1;
    }

    let ret
    if (alphabetic) {
      ret = alphabeticCollator.compare(a, b)
    } else {
      ret = naturalCollator.compare(a, b)
    }
    if (descending) {
      ret = -ret
    }
    return ret
  };
}

const items = [null, 10, 1, 100, null, 'hello', .1, null]

console.log(items.sort(nullSort()));

Solution 6 - Javascript

like this, note: this will only push the null's to the back

var arr = ["a", null, "b"];
var arrSor = [];
arr.forEach(function (el) {

    if (el === null) {
        arrSor.push(el);
    } else {
        arrSor.unshift(el);
    }
});

Solution 7 - Javascript

Do it like:

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

        foreach ($arr as $key => $value) {
           if($value == null)
		   unset($arr[$key]);
           $arr[] = $value;

        }
        // rebuild array index
        $arr = array_values($arr);

        echo '<pre>';print_r($arr);die;

Solution 8 - Javascript

I am sorting objects with a custom index and this works for me. I am not wanting to change the original array and it is important to keep the null indexes where they are.

let sorted = [...array].sort((a, b) => {
               if (!a || !b) return 0;
               else return a.CustomIndex - b.CustomIndex;
             });

Solution 9 - Javascript

function sortNumsAsc(arr) {
    if(arr === null || arr === []) {
        return [];
    }
    else {
	return arr.sort(function(a,b){return a-b});
	//return newarr;
    }
}
console.log(sortNumsAs([801, 19, 4, 5, -4, 85]))

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSirkView Question on Stackoverflow
Solution 1 - JavascriptAntouanKView Answer on Stackoverflow
Solution 2 - JavascriptBergiView Answer on Stackoverflow
Solution 3 - JavascriptcegprakashView Answer on Stackoverflow
Solution 4 - JavascriptPaul RoubView Answer on Stackoverflow
Solution 5 - JavascriptSteven SpunginView Answer on Stackoverflow
Solution 6 - JavascriptVitaliy TerzievView Answer on Stackoverflow
Solution 7 - JavascriptShubhamView Answer on Stackoverflow
Solution 8 - JavascriptMichael Aaron WilsonView Answer on Stackoverflow
Solution 9 - JavascriptS GabaleView Answer on Stackoverflow