mihaifm / linq

linq.js - LINQ for JavaScript

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

orderBy not working with null values

jordanbrowneb opened this issue · comments

We're getting some really weird behavior when using orderBy on arrays with null in them.

Below is a test case running linq 3.2.1 on node 10.15.3.

const Enumerable = require('linq');

const data = ['2019-10-01', null, '2019-09-12', '2019-09-15', null];
const result = Enumerable.from(data).orderBy(x => x).toArray();

result.forEach(x => console.log(x));

Expected output:

null
null
2019-09-12
2019-09-15
2019-10-01

Actual output:

2019-10-01
null
2019-09-12
2019-09-15
null

Thanks in advance for any help you can provide.

This is the function used for comparison:

compare: function (a, b) {
            return (a === b) ? 0
                 : (a > b) ? 1
                 : -1;
        }

Values are reversed if (a>b).
Unfortunately comparing something with null always returns false.

console.log('2019-09-12' > null)
false

console.log('2019-09-12' < null)
false

One solution would be to pass a better lambda to orderBy, causing the value to be sanitized before comparing:

const result = Enumerable.from(data).orderBy(x => (x===null) ? "" : x).toArray();

Thank you for your quick reply. Do you intend to change the library to better handle nulls like in this case? Or is the workaround you posted going to be the permanent solution?

Not sure yet...
array.sort() does indeed sort the above values but it does so by converting nulls to strings.

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

We can probably do the same for this library using some typeof wizzardry, but it feels like a very specific scenario.

Gotcha. It's a fairly common use case for us ( e.g. calling .select(...) to grab a nullable property then sorting it using .orderBy(...) ).

We were surprised that the order returned was not the same as when doing the equivalent calls in C# LINQ. C# will return the expected output I listed earlier.

This is the function used for comparison:

compare: function (a, b) {
            return (a === b) ? 0
                 : (a > b) ? 1
                 : -1;
        }

Values are reversed if (a>b).
Unfortunately comparing something with null always returns false.

console.log('2019-09-12' > null)
false

console.log('2019-09-12' < null)
false

One solution would be to pass a better lambda to orderBy, causing the value to be sanitized before comparing:

const result = Enumerable.from(data).orderBy(x => (x===null) ? "" : x).toArray();

I suddenly realized that Intl could solve this problem
image

Now , you can set compare function , at 3.2.2
Issue: #74

const a= ['2019-10-01', null, '2019-09-12', '2019-09-15', null];
var cf = new Intl.Collator();
Enumerable.from(a).orderBy(x=>x, cf.compare).toArray()

output:
["2019-09-12", "2019-09-15", "2019-10-01", null, null]

You can prepare a custorm compare function to let null in front.

warning:

You should have a reasonable initialization parameter,otherwise the result may not be what you want.
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Collator

Example:

var cf = new Intl.Collator();
cf.compare(1,2)
//=-1
cf.compare(15,2)
//=-1  (Expected = 1)