jonschlinkert/array-sort

After sorting, empty strings are at the beginning of the sorted array

vladshcherbin opened this issue · 6 comments

const test = [
  { title: 'b' },
  { title: '' },
  { title: 'a' }
]

console.log(arraySort(test, 'title'))

Output:

[
  { title: '' },
  { title: 'a' },
  { title: 'b' }
]

Expected output:

[
  { title: 'a' },
  { title: 'b' },
  { title: '' }
]

Since it's sorting by string, I'd expect empty strings to be last in the array, similar to null values.

doowb commented

The sorting logic follows what would happen if you sort an array with just the values:

var arr = ['', null, undefined, 'a', 'c', 'b'];
console.log(arr.sort());
//=> ['', 'a', 'b', 'c', null, undefined]

I think this makes sense since an empty string can be compared to another string, but null and undefined always return false:

console.log('' > 'a');
//=> false
console.log('' < 'a');
//=> true
console.log(null > 'a');
//=> false
console.log(null < 'a');
//=> false
console.log(undefined > 'a');
//=> false
console.log(undefined < 'a');
//=> false

I think if you need different functionality, then you can pass in a custom compare function

@doowb in your example, I'd expect result to be:

var arr = ['', null, undefined, 'a', 'c', 'b'];
//=> ['a', 'b', 'c', '', null, undefined]

Here is a more real-world example: you have movies and you want to sort them alphabetically by movie director. If a movie doesn't have a specified director, it will be at the beginning of the sorted array.
I'd expect to see movies with specified director first, starting from A to Z and movies with no specified director at the end.

const movies = [
  { title: 'Movie 1', director: 'Bill' },
  { title: 'Movie 2', director: '' },
  { title: 'Movie 3', director: 'Alex' }
]
arraySort(movies, 'director')

// current
[
  { title: 'Movie 2', director: '' },
  { title: 'Movie 3', director: 'Alex' },
  { title: 'Movie 1', director: 'Bill' }
]

// expected
[
  { title: 'Movie 3', director: 'Alex' },
  { title: 'Movie 1', director: 'Bill' },
  { title: 'Movie 2', director: '' }
]
doowb commented

My example was showing how the native JavaScript sort works and that '' will sort to the beginning.

In your example, director is undefined so it will sort to the end as you expect.

image

I also did some tests in excel to see how an empty string is sorted and it will go to the beginning for ascending and end for descending.

We refactored the default comparison logic (that handles null and undefined) into default-compare so you can use it with a custom function to do the sorting that you're expecting:

var defaultCompare = require('default-compare');

function compare(prop) {
  return function(a, b) {
    var aVal = a && a[prop];
    var bVal = b && b[prop];

    if (aVal === '' && bVal !== '') {
      return 1;
    } else if (aVal !== '' && bVal === '') {
      return -1;
    }

    return defaultCompare(a, b, prop);
  };
}

var arr = [
  { title: 'Movie 1', director: 'Bill' },
  { title: 'Movie 2', director: '' },
  { title: 'Movie 3', director: 'Alex' }
];

console.log(arraySort(arr, compare('director')));

@doowb yeah, I can even provide a custom function to array.sort() and don't use any libraries. :)

The whole point of using a library to sort arrays is convenience. If you think, that default sort is working correctly and empty strings should be first in array, then I guess I just need to find another library where empty strings are at the end of sorted array.

I missed director field in my example, fixed it some minutes later.

As an idea, there could be options for such cases:

arraySort(array, comparisonArgs, options?);

// movies
arraySort(movies, 'director', { emptyStringsLast: true })
doowb commented

If you think, that default sort is working correctly and empty strings should be first in array, then I guess I just need to find another library where empty strings are at the end of sorted array.

That's fine, that's why this is open source :) I based my decision on how native JavaScript sorts arrays, how excel is doing it, and how I've seen other libraries sort.

there could be options for such cases:

If you'd like to do a PR for discussion, we'll take a look at it.