5

I have this array

$array = array(2, 1, "img1", "img2", "img10", 1.5, "3.14", "2.72");

after applying sort function it becomes

sort($array);

Array
(
    [0] => 2.72
    [1] => 3.14
    [2] => img1
    [3] => img10
    [4] => img2
    [5] => 1
    [6] => 1.5
    [7] => 2
)

I did't understand how the sorting is performed.

Can anyone explain how the output array is achieved?

EDIT:

Here the question is not that which SORT FLAG should I use but the question is how the above sorting is performed. Any advise to use another SORT FLAG is useless here.

3
  • 3
    Set the SORT_NUMERIC flag php.net/sort Commented Feb 7, 2013 at 14:28
  • @Pekka웃: I really want to know How the sorting is performed even with SORT_REGULAR. What does SORT_REGULAR mean? How sort regular assign priority to the items in the sort result? Commented Feb 7, 2013 at 14:31
  • So i'm pretty sure I figured out the answer to this, I will post it later tonight when I get home (unless someone beats me to it). Commented Feb 7, 2013 at 19:28

3 Answers 3

6

The first two numbers were actual strings (you passed them within quotes), so they are treated like so: numbers come before any letter in alphabetic sorting.

The other ones were real numbers (without quotes), so the function put them separately, sorting them numerically.

array(8)
    0 => '2.72'    [alphabetical]
    1 => '3.14'    [alphabetical]
    2 => 'img1'    [alphabetical]
    3 => 'img10'   [alphabetical]
    4 => 'img2'    [alphabetical]
    5 => 1         [numeric]
    6 => 1.5       [numeric]
    7 => 2         [numeric]

So, the function has to decide if it will sort the elements alphabetically (a,b,c...) or numerically (1,2,3..) so it just checks the variable type.

Like Pekka pointed out, there are flags that can be set to force the type of sorting. They are described in the docs.


EDIT

This theory was proved wrong in the comments and I'm totally lost now (:

This comment at the docs contains some interesting points on this issue.

Sign up to request clarification or add additional context in comments.

6 Comments

Can you expand your answer? I'm really not getting, this will be a great help if you can explain further.
This does not answer what compare algorithm is being used on the backend, and to me this is what the question is asking. In an expected result, numbers would come before strings. This is true of almost all sorts you find, especially due to ascii values. Why would php implement numbers to sort second? I have checked documentation and ran some tests, the sort functions does not use the standard operators (==,<,>), strcmp(), ord(). Does anybody know what it does use in its implementation of sort() with no flags?
what i'm trying to say is that it appears to be using BOTH numerical AND alphabetical sorting, depending on the types you passed as argument. Numbers are comming first in the alphabetical sorting, but the alphabetical sorting itself is comming before the numerical sorting.
Let me show you that you wrong, look at the link @coanda provided. If you have a chance sort this array: ("a","b","4",5,4,"true","TRUE",true, false, "c", "d"). And then sort this array: ("a","b","4",5,4,"true","TRUE",true, false, "c"). These return 2 completely different results by just removing "d" element. According to PHP this is not a bug, but rather the result of type juggling.
And me too now very much confused with the sorting algorithm with the mixed typed array and trying the various sorting flags on this type of array. Really needs to get actual algorithm of sorting with all the sort flags. Hope someone will back with the same
|
3

Using the information in the link for Coanda as a starting point, it is clear that PHP using type juggling when comparing objects of different types. The problem is understanding what is getting casted to what during comparison, and I still havn't been able to find a complete list, but in general:

string compared to int will turn into

(int) string <,>,=, (int) int 

In this case the string, after casting becomes 0, so all ints are greater than a string. (expected). This is the only case we need to worry about for this sort.

PHP uses quicksort, and most likely chooses its pivot point as array[n/2] where n is the number elements in the array. Knowing these two pieces of information we quicksort the above array:

$pivot = $array[n/2] //n is the number of elements, this sets $pivot='img2'
//compare each element in the list (i am going to this by hand for demonstration)

(int) 'img2' < 2 //int to int comparison;'img2' resolves to 0 and 0 < 2
(int) 'img2' < 1 //int to int comparison;'img2' resolves to 0 and 0 < 1
      'img2' > 'img1' // string to string comparison; strcmp is +256 
      'img2' > 'img 10' //string to string comparison; strcmp is +256 
(float) 'img2' < 1.5 //float to float comparison;'img2' resolves to 0 and 0<1.5 
      'img2' > '3.14' //string to string comparison; strcmp is +54
      'img2' > '2.72' //string to string comparison; strcmp is +55

We now have to two new arrays (one for greater and one for less than).

 $greater = array('img1', 'img10', '3.14', '2.72);
 $less = array(2, 1, 1.5);

Now there is little need to go into further detail as we have accidentally made 2 arrays that have all easily comparable objects in it. $greater has only strings, and we can assume sort will work normally here and considering everything a string.

sort($greater);
var_dump($greater);

produces

array(4) {
  [0]=>
  string(5) "2.72"
  [1]=>
  string(4) "3.14"
  [2]=>
  string(4) "img1"
  [3]=>
  string(5) "img10"
}

This is what we expected and also the result above. We do the same with $lesser

$lesser = array(2, 1, 1.5);
sort($lesser);
var_dump($lesser);

we get

array(3) {
  [0]=>
  int(1)
  [1]=>
  float(1.5)
  [2]=>
  int(2)
}

Which is also expected. Now when we concat all three arrays together (for the sake of recursiveness I am calling 'img2' an array). We get the results above.

Array
(
[0] => 2.72
[1] => 3.14
[2] => img1
[3] => img10
[4] => img2
[5] => 1
[6] => 1.5
[7] => 2
)

To prove this point, you can follow the same process for this same array, but switch out the $arr[3] with an integer.

$arr = array("img2", 1, "img1", 2, "img10", 1.5, "3.14", "2.72");
sort($arr);
var_dump($arr)

gives you a totally different result because the pivot changed from a string to an int causing the float strings to evaluate as floats.

array(8) {
[0]=>
string(4) "img1"
[1]=>
string(5) "img10"
[2]=>
string(4) "img2"
[3]=>
int(1)
[4]=>
float(1.5)
[5]=>
int(2)
[6]=>
string(4) "2.72"
[7]=>
string(4) "3.14"
}

Comments

1

The following bug gives more insight in sorting mixed types: https://bugs.php.net/bug.php?id=21728

Quote:

<?php
$arr1 = array("a","b","c","d","4",5,4,"true","TRUE",true);
sort($arr1);
var_dump($arr1);
?>

The output is :
array(10) {
  [0]=>
  bool(true)
  [1]=>
  int(4)
  [2]=>
  string(1) "4"
  [3]=>
  string(4) "TRUE"
  [4]=>
  string(1) "a"
  [5]=>
  string(1) "b"
  [6]=>
  string(1) "c"
  [7]=>
  string(1) "d"
  [8]=>
  string(4) "true"
  [9]=>
  int(5)
}

It may look strange - why (int)5 is after all the strings. This is because "4" is lower than (int) 5, "4" is before "true" and "true" is before 5. The first 2 are obvious, the third one is not. But it is ok. It's better not to mix types in the array. If 5 is changed to "5" then "5" goes right after "4".

1 Comment

I write my own sorting functions when I have mixed types. The function usort is easy and effective to use. See link. I think it is very difficult to predict the outcome of PHP's own sort function.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.