dbrockman / compare-property

Javascript array sort compare util
4 stars 1 forks source link

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

Open vladshcherbin opened 7 years ago

vladshcherbin commented 7 years ago
const array = [
  { title: 'b' },
  { title: '' },
  { title: 'a' }
]

console.log(array.sort(compare.property('title', 1)))

Output:

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

Expected output:

Since it's sorting by string, I'd expect empty strings to be last in the array:

[
  { title: 'a' },
  { title: 'b' },
  { title: '' }
]
alexindigo commented 7 years ago

This is how Javascript sorts strings.

['b', '', 'a'].sort()
// -> ["", "a", "b"]

in more generic case, how you'd want to sort this array?

['ab', 'a', 'aa'].sort()
// -> ["a", "aa", "ab"]

^ as you can see a + <empty string> goes before a + a.

vladshcherbin commented 7 years ago

@alexindigo I'd like to have a possibility to sort it this way:

ascending
['b', '', 'a'] -> ['a', 'b', '']

descending
['b', '', 'a'] -> ['b', 'a', '']
alexindigo commented 7 years ago

Something like this would do the job:

['b', '', 'a'].sort((a, b) => !a ? 1 : !b ? -1 : a > b) // ascending
// -> ["a", "b", ""]
['b', '', 'a'].sort((a, b) => !a ? 1 : !b ? -1 : a < b) // descending
// -> ["b", "a", ""]
vladshcherbin commented 7 years ago

@alexindigo oh, yes, I know how to manually sort this, thank you.

I wanted to find a library that already has this algorithm, with a possibility to use multiple properties for sorting. Could not find any with such sorting algorithm.

alexindigo commented 7 years ago

Sounds like somewhat unusual use case, so you might need to roll out your own. In the same time, this library has support for multiply properties sorting:

compare.properties({ age: -1, name: 1 }, ['name']);

So if you create PR, where it would support functions along with numbers, then you can get your custom sorting on per property basis, with "heavy" lifting done by the library.

Something like

compare.properties({ age: -1, name: (a, b) => !a ? 1 : !b ? -1 : a > b }, ['name']);
vladshcherbin commented 7 years ago

@alexindigo I actually find my use case pretty common and I don't understand, why there are so many sorting libraries and none of them has a built-in solution.

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

alexindigo commented 7 years ago

Looks like it overlaps with filtering and a bit more than just sorting. But I see your point, so there is a niche for some kind of "human sorting" library, that would do exactly that and maybe ignore things like "the" as well. :)

vladshcherbin commented 7 years ago

@alexindigo yeah, a "human sorting" library 😄