While writing some software for work which works out distances between geographic locations, I discovered some nastiness with the natsort() function in php.
This function implements a sort algorithm that orders alphanumeric strings in the way a human being would while maintaining key/value associations. This is described as a “natural ordering”.
So, given this definition of natsort, I’ll now outline a working example and then an example of the problem I encountered.
Lets say we have a list of values in an array that need to be sorted descending whilst maintaining key/value pairs. E.g:
$a = array(4 => 9.1, 3 => 4.2, 10 => 4.5); natsort($a);
As you would expect, the resulting array looks a little something like this.
print_r($a); Array ( [3] => 4.2 [10] => 4.5 [4] => 9.1 )
But what happens when the values in the array we are trying to sort are a little more complex:
$a = array(4 => 9.11705244995,3 => 4.23956628237,10 => 4.5361796771); natsort($a);
The resulting array isn’t what we expect though.
print_r($a); Array ( [10] => 4.5361796771 [3] => 4.23956628237 [4] => 9.11705244995 )
As you can see, the sort order is incorrect. As you have probably picked up, the 4.5xxx number’s decimal places are 1 less than the other two numbers. As soon as you change 4.5361796771 to 4.53617967711 and run natsort() over it, it returns the correct order.
Conclusion: Don’t use natsort() when sorting floats of different precision as it will return incorrect values! Use something like asort() if you want to maintain key/value pairs, or sort() if you don’t care about the key ordering.
Tags: natsort, php, programming, sorting
If you’re in a bind, you can multiply those values by X, natsort, then divide each by X. Not elegant, but it works.
Very true. But if you multiplied out to integers, then you might as well use the standard sort function to order them, then divide back out.
Easier to just use sort().