Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multisorting mixed associative arrays

Status
Not open for further replies.

MacTommy

Programmer
Feb 26, 2007
116
NL
I am not sure if it is a bug or a feature but if I try the following code
Code:
$aTest = array( '3 ' => array('a' => '3a',
			   'b' => '3b'),
		'a' => array('a' => 'aa',
			    'b' => 'ab'),
		'5 ' => array('a' => '5a',
			    'b' => '5b') );

printArr($aTest);

array_multisort(array_keys($aTest), SORT_ASC, SORT_STRING, $aTest);

print "===================================<br>";
printArr($aTest);

function printArr($aArr) {
  print "<pre>";
  print_r($aArr);
  print "</pre>";
}

This puts out:
Code:
Array
(
    [3 ] => Array
        (
            [a] => 3a
            [b] => 3b
        )

    [a] => Array
        (
            [a] => aa
            [b] => ab
        )

    [5 ] => Array
        (
            [a] => 5a
            [b] => 5b
        )

)

===================================

Array
(
    [3 ] => Array
        (
            [a] => 3a
            [b] => 3b
        )

    [5 ] => Array
        (
            [a] => 5a
            [b] => 5b
        )

    [a] => Array
        (
            [a] => aa
            [b] => ab
        )

)
However, if I use this array:
Code:
$aTest = array( '3' => array('a' => '3a',
			   'b' => '3b'),
		'a' => array('a' => 'aa',
			    'b' => 'ab'),
		'5' => array('a' => '5a',
			    'b' => '5b') );
I get:
Code:
Array
(
    [0] => Array           <-- Where did the '3' go???
        (
            [a] => 3a
            [b] => 3b
        )

    [1] => Array            <-- Where did the '5' go???
        (
            [a] => 5a
            [b] => 5b
        )

    [a] => Array
        (
            [a] => aa
            [b] => ab
        )

)
after the sorting.
Suddenly my indexes are gone.
I guess what happens is that they are converted to integers somewhere down the line.
However, it messes up my data because I actually want to have the >>string<< '3' there.

Any suggestions on how to get PHP do this..?!?

I tried single quotes, double quotes, enclosing the keys in a strval(), and casting them explicitly by using (string).
All to no avail...
 
What's going on is that in the second example, the numbers are getting
converted to array indexes 0 and 1.

Notice that in the first example you have: ['3 '] & ['5 '] and in the second you
have: ['3'] & ['5']. Note the trailing space in the first example.

Note this from the beginning of PHP's documentation on array_multisort():

[tt]
Returns TRUE on success or FALSE on failure.

array_multisort() can be used to sort several arrays at once, or a multi-dimensional array by one or more dimensions.

Associative (string) keys will be maintained, but numeric keys will be re-indexed.
[/tt]

So, if you want to maintain the numeric indexes, you'll need to pre-check
your indexes and append a space if one is numeric before executing
array_multisort() and possibly, convert back when done.
 
Yes, exactly. That is right of course.

I was just wondering whether there would be a way I could force PHP to think of these indexes as strings rather than numbers, because I would rather not mess with the data (in the solution you sketched out I would have to keep track of when the appended space was part of the original data, or appended by me...).
 
this looks like a bug to me.

but i do not thing that you need to use multi_sort for the above. just use ksort with SORT_STRING

 
No, darrellblackhawk is right. It is not a bug, it is a documented feature. Though you might doubt its advantage of course.
 
Yes you would, but that's relatively trivial if the size of the array is small.

You just do a foreach over the source array and store the first index into a
two column comparator array.

While iterating over the source array, you perform a
boolean is_numeric(on the trimmed value of the index value)
placing the resulting boolean value into the second column
of the comparator array.

At the same time, you then make sure all array indexes that are
numeric have a space(s) appended. Alpha indexes are left unchanged
and don't get added to the comparator array - or they can, but that's a waste.

After performing the multi-sort, you step back through the source array and
remove the spaces based on the stored values in the comparator array.

Result:
The array indexes aren't munged and you have a nicely ordered array.

Note: If you have multiple indexes with the same numeric value, you will
have to do a lookup in the comparator array and append an extra space so
the original is not overwritten.

i.e.

Code:
<?php
 $a = array('5' => 'hello', '5' => 'goodbye');
 $b = array('5 ' => 'hello', '5' => 'goodbye');
 print '<pre>';
 print_r($a);
 print_r($b);
 print '</pre>';
 exit;
?>


 
scratch my diatribe vis-a-vis the comparator array.

jpadie is correct regarding the ksort()

if you have multiple numeric indexes with the same value, there's probably
something wrong with the data - even if one is '5' and the other is '5 '.
 
i think it is a bug, related to loose casting. i'll review the source code when i have a moment.

multisort will only reorg the keys if they are numeric. you are not using numeric keys but during the process of sorting, the keys are being recast loosely. since you are expressly specifying a string value, this behaviour is not consistent with the documentation.

anyway, ksort will do the necessary.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top