1
\$\begingroup\$

I'm sorting my object by its property ActivityOrder, which will sometimes contain null values if the user has not explicitly stated an order which an activity should appear.

Since null will always appear top most in the sort (unless reversed), it messed up my sort.

The solution I came up with was to sort by the id if activityOrder was null since the ID will always be greater than the activityOrder within our application and then there is some logical order to the sort too.

var data = [{
        "id": 150,
        "name": "Andrew",
        "activityOrder": null
}, {
        "id": 151,
        "name": "Andrew",
        "activityOrder": null
}, {
        "id": 152,
        "name": "Andrew",
        "activityOrder": 1
}];


data = _.sortBy(data, function(o) {
        if (o.activityOrder === null)
            return o.id;
        return o.activityOrder
});

_.each(data, function(x) {
        $('#cnt').append("<tr><td>" + x.Name + " - Order " + x.activityOrder + "</td></tr>")
})

I had also tried amending the value if the activityOrder null to 99999999999 and resetting it back to null after doing whatever. I didn't like the idea of this one.

data = _.sortBy(data, function(o) {
        if (o.activityOrder === null)
            o.activityOrder = 99999999999;
        return o.activityOrder
});

//Do whatever

//Reset Activity Order back
_.each(d, function(o) {
        if (o.activityOrder === 99999999999) {
                o.activityOrder = null;
        }
});

How best would you sort an object array by a property which contains null values?

\$\endgroup\$
3
\$\begingroup\$

flapdoodle!

if (o.activityOrder === null)
        o.activityOrder = 99999999999;

Dude, don't do this. Really.


Sorting idiom

  • Javascript supports sorting pretty much as you'll see in other languages.
  • Collections have sorting.
  • Sort functions can take a function delegate for customized sorting.
  • Typically, compare the desired values and return an integer that means less-than, equal-to, greater-than. Typically -1, 0, 1 respectively.
  • handling null does not require converting it to a valid value in your set domain.
  • Read the documentation!
\$\endgroup\$
1
\$\begingroup\$

To be fair, a null can't really be sorted within a group of sortable objects. You'll end up with the nulls beside each other every time, where they lay is the question. I take it you wanted to sort the array WITHOUT looking at nulls? i.e.

1, null, null, 10, 1, null, 73, 5

should become

1, null, null, 1, 5, null, 10, 73

Is this what you want?

Edit: Woops I mistook this post for Java. Does Javascript offer a comparator interface or implementation? I suggest you look towards making your own sort algorithm to sort how you want, but excluding any comparisons on a proper int versus null.

\$\endgroup\$
  • \$\begingroup\$ Not particularly, I wanted the nulls to be treated as a "high number" when sorting by ascending. 1 , 2, 24, null, null and a "low number" when descending. I think my method will be a fair solution to the problem within my application. I was just curious as to whether there were any hidden gems when dealing with them. \$\endgroup\$ – ZeroBased_IX Jul 28 '15 at 9:14
  • \$\begingroup\$ @Jezzabeanz Ah I understand. I think sorting with nulls at one end is easy, sorting with them at both ends based on a choice of desc/asc is the trickier part. I definitely think there's a way around the 99999... variable swap. \$\endgroup\$ – insidesin Jul 28 '15 at 9:21
  • \$\begingroup\$ Yep, just found it. If I just return 99999 or Infinity then that should solve it. The ascending / descending could be done with a simple function which takes an optional parameter function sortObject(data, ascending=true) \$\endgroup\$ – ZeroBased_IX Jul 28 '15 at 9:27
0
\$\begingroup\$

Here is a javascript function based on lodash's functions that allows the sort of array of objects with null and undefined always at the end (ascending and descending order) of the resulting array (copy). It allows ordering on sub-properties (ex: 'parcel.purchaser.name')

function orderByWithNullsAtEnd(pArray: any[], pAttr: string, pReverse: boolean) {
  const partition = _.partition(pArray, (x) => !!_.get(x, pAttr, null));
  return _.concat(_.orderBy(partition[0], pAttr, (pReverse ? 'desc' : 'asc')), partition[1]);
}

The advantages of this solution are:

  • genericity; that's work with all datatypes (of fields)
  • put all the null (or undefined) at the end
  • based on a well-known library (lodash)
  • can be easily improve to do the same for empty string values
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.