Narusegawa
asked on
USort with Multi Lveel Array
I'm trying to sort an array by a field several levels deep, but I just can't get it to work.
My array is
And I'm trying to sort using this function. $standings is the array from above.
However I just can't get it to work, I can sort simple arrays but this one is starting to get to me.
I want to get the child arrays sorted by the "Standing" field which is a simple float field. (includes negative)
I'd be appreciative of any quick answer to this. Thanks!
My array is
Array
(
[0] => Array
(
[standingType] => agents
[standings] => Array
(
[0] => Array
(
[fromID] => 3009559
[fromName] => Ancevence Achelasse
[standing] => 2.36
[standingType] => agents
)
[1] => Array
(
[fromID] => 3009560
[fromName] => Gryncelbois Erris
[standing] => -0.01
[standingType] => agents
)
)
)
[1] => Array
(
[standingType] => NPCCorporations
[standings] => Array
(
[0] => Array
(
[fromID] => 1000005
[fromName] => Hyasyoda Corporation
[standing] => 0.21
[standingType] => NPCCorporations
)
[1] => Array
(
[fromID] => 1000047
[fromName] => Krusual Tribe
[standing] => 0.18
[standingType] => NPCCorporations
)
)
)
[2] => Array
(
[standingType] => factions
[standings] => Array
(
[0] => Array
(
[fromID] => 500001
[fromName] => Caldari State
[standing] => -2.26
[standingType] => factions
)
[1] => Array
(
[fromID] => 500002
[fromName] => Minmatar Republic
[standing] => 3.03
[standingType] => factions
)
)
)
)
And I'm trying to sort using this function. $standings is the array from above.
usort($standings, 'standingStandingSort');
function standingStandingSort($a, $b) {
if ($a['standings']['standing'] < $b['standings']['standing'])
return 0;
return ($a['standings']['standing'] < $b['standings']['standing']) ? -1 : 1;
}
However I just can't get it to work, I can sort simple arrays but this one is starting to get to me.
I want to get the child arrays sorted by the "Standing" field which is a simple float field. (includes negative)
I'd be appreciative of any quick answer to this. Thanks!
you should use something like this:
i am not sure that i got it right, you should double check. this will sort each on in turn.
foreach($standings)
usort($standings['standings'], 'standingStandingSort');
function standingStandingSort($a, $b) {
if ($a['standing'] < $b['standings'])
return 0;
return ($a['standings'] < $b['standings']) ? -1 : 1;
}
i am not sure that i got it right, you should double check. this will sort each on in turn.
ASKER
I think I've been a little silly. I just realized that it's an Array of Objects.
If I do this
The print_r($a) returns this :
I tried your suggestion, but then I got told that I can't do that with an Object.
If I do this
function standingStandingSort($a, $b) {
print_r($a);
if ($a->standings[0]['standing'] < $b->standings[0]['standing'])
return 0;
return ($a->standings[0]['standing'] < $b->standings[0]['standing']) ? -1 : 1;
}
The print_r($a) returns this :
Array
(
[standingType] => NPCCorporations
[standings] => Array
(
[0] => standingItem Object
(
[fromID] => 1000005
[fromName] => Hyasyoda Corporation
[standing] => 3.21
[standingType] => NPCCorporations
)
[1] => standingItem Object
(
[fromID] => 1000047
[fromName] => Krusual Tribe
[standing] => 5.18
[standingType] => NPCCorporations
)
)
I tried your suggestion, but then I got told that I can't do that with an Object.
foreach($standings as $k => $v)
usort($standings[$k]['standings'], 'standingStandingSort');
function standingStandingSort($a, $b) {
if ($a['standing'] < $b['standing'])
return 0;
return ($a['standing'] < $b['standing']) ? -1 : 1;
}
this should work
ASKER
Thanks for the help, I am getting the same error I had too.
"Fatal error: Cannot use object of type standingItem as array in /var/www/vhosts/plugin.php on line 114"
Line 114 is this line
"Fatal error: Cannot use object of type standingItem as array in /var/www/vhosts/plugin.php
Line 114 is this line
if ($a['standing'] < $b['standing'])
hang on a second, i am copying the array and trying it myself, faster this way
ASKER
Thanks, I really appreciate the help. I knew mixing objects and arrays was gonna be a pain.
Can you post a link to some test data - preferably generated in PHP? Sorting an array of objects is a fairly well understood process. You're on the right path with usort()
<?php
$standings=Array(Array('standings'=>Array(Array('standing'=>1.5),Array('standing'=>0.5))), Array('standings'=>Array(Array('standing'=>2.5),Array('standing'=>0.6))));
function cmp($a, $b){
if ($a['standing']==$b['standing'])
return 0;
return ($a['standing'] < $b['standing']) ? -1 : 1;
}
foreach($standings as $k => $v){
usort($standings[$k]['standings'], 'cmp');
}
print_r($standings);
?>
there you have it :D
@andreizz: That looks right - I have not tested it, but the standard usort() function seems to be implemented the usual way. However Narusegawa indicated that the issue was sorting an array of objects (ID:34933046), and that would have a little bit different notation, not quite the same as an array of arrays. Maybe if we can get the classes used to create the objects we can give a more precise answer.
I think what i have posted is exactly what he wanted, let's wait for his answer.
Sure. Look at the example posted here: ID:34932897 -- that would seem to require OOP notation.
ASKER
I'm just trying to get some code together that'd provide the same data structure that I am working with.
function standingStandingSort($a, $b){
if ($a['standing']==$b['standing'])
return 0;
return ($a['standing'] < $b['standing']) ? -1 : 1;
}
foreach($standings as $k => $v){
usort($standings[$k]['standings'], 'standingStandingSort');
}
print_r($standings);
ASKER
I'll just test that now andreizz.
To replicate the same array of objects I am using, this is the code.
You will get something like this
And it's the standings sub-arrays that need sorting, inside their respective sections. Order by decending "standing" float field.
i.e
The result I'm looking to achieve is this :
To replicate the same array of objects I am using, this is the code.
<?php
ini_set('display_errors','1');
class standingItem {
var $fromID = 0;
var $standing = 0;
var $standingType = '';
}
$standing1 = new standingItem;
$standing1->fromID = '1000005';
$standing1->standing = '1.5';
$standing1->standingType = 'Type1';
$standing2 = new standingItem;
$standing2->fromID = '1000006';
$standing2->standing = '7';
$standing2->standingType = 'Type1';
$standing3 = new standingItem;
$standing3->fromID = '1000007';
$standing3->standing = '-5';
$standing3->standingType = 'Type2';
$standing4 = new standingItem;
$standing4->fromID = '1000008';
$standing4->standing = '8';
$standing4->standingType = 'Type2';
$standings = Array(
'Type1'=> Array(
'standingType'=>'Type1',
'standings'=>Array($standing1,$standing2),
),
'Type2'=> Array(
'standingType'=>'Type2',
'standings'=>Array($standing3,$standing4),
)
);
print_r( $standings );
?>
You will get something like this
Array
(
[Type1] => Array
(
[standingType] => Type1
[standings] => Array
(
[0] => standingItem Object
(
[fromID] => 1000005
[standing] => 1.5
[standingType] => Type1
)
[1] => standingItem Object
(
[fromID] => 1000006
[standing] => 7
[standingType] => Type1
)
)
)
[Type2] => Array
(
[standingType] => Type2
[standings] => Array
(
[0] => standingItem Object
(
[fromID] => 1000007
[standing] => -5
[standingType] => Type2
)
[1] => standingItem Object
(
[fromID] => 1000008
[standing] => 8
[standingType] => Type2
)
)
)
)
And it's the standings sub-arrays that need sorting, inside their respective sections. Order by decending "standing" float field.
i.e
The result I'm looking to achieve is this :
Array
(
[Type1] => Array
(
[standingType] => Type1
[standings] => Array
(
[0] => standingItem Object
(
[fromID] => 1000006
[standing] => 7
[standingType] => Type1
)
[1] => standingItem Object
(
[fromID] => 1000005
[standing] => 1.5
[standingType] => Type1
)
)
)
[Type2] => Array
(
[standingType] => Type2
[standings] => Array
(
[0] => standingItem Object
(
[fromID] => 1000008
[standing] => 8
[standingType] => Type2
)
[1] => standingItem Object
(
[fromID] => 1000007
[standing] => -5
[standingType] => Type2
)
)
)
)
the above script should work if you just paste it in your php script
ASKER
Fatal error: Cannot use object of type standingItem as array in /var/www/vhosts/plugin.php on line 78
Line 78 : if ($a['standing']==$b['stand ing'])
Which is the second line in your function :(
Line 78 : if ($a['standing']==$b['stand
Which is the second line in your function :(
i think you need to lose the usort function and do a simple comparison and just switch the values between them.
if you don't manage i'll try again to make a example.
if you don't manage i'll try again to make a example.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
andreizz you are a star. I was just about to start looking into maybe sorting the data at an earlier stage (when it's still xml). But this works awesome! Thanks!
No problem :D anytime :D
Thanks to you i now have a premium account! :D
Thanks to you i now have a premium account! :D
This worked for me, but you might want to exercise some caution about comparing floating point values. It seems that the numeric range of the possible values of "standing" could be important. See the notes in the man page link given on line 50. You might want to use sprintf() or something to cast the "standing" into something that avoids the cautionary tales about float values. Of course, if you are not doing arithmetic with the standings or if you are always setting that field with number_format() to limit the precision you should be OK.
<?php // RAY_temp_narusegawa.php
ini_set('display_errors', TRUE);
error_reporting(E_ALL);
echo "<pre>";
class standingItem
{
public $fromID = 0;
public $standing = 0;
public $standingType = '';
}
$standing1 = new standingItem;
$standing1->fromID = '1000005';
$standing1->standing = '1.5';
$standing1->standingType = 'Type1';
$standing2 = new standingItem;
$standing2->fromID = '1000006';
$standing2->standing = '7';
$standing2->standingType = 'Type1';
$standing3 = new standingItem;
$standing3->fromID = '1000007';
$standing3->standing = '-5';
$standing3->standingType = 'Type2';
$standing4 = new standingItem;
$standing4->fromID = '1000008';
$standing4->standing = '8';
$standing4->standingType = 'Type2';
$standings = array(
'Type1'=> Array(
'standingType'=>'Type1',
'standings'=>Array($standing1,$standing2),
),
'Type2'=> Array(
'standingType'=>'Type2',
'standings'=>Array($standing3,$standing4),
)
);
// SHOW THE ORIGINAL ORDER
var_dump($standings);
// A FUNCTION TO COMPARE BY STANDINGS
function cmp($thing1, $thing2)
{
// CAST NUMBERS IN A CONSISTENT MANNER BUT SEE WARNING HERE: http://www.php.net/manual/en/language.types.float.php
$a = (float)$thing1->standing;
$b = (float)$thing2->standing;
echo PHP_EOL . "$a $b";
// COMPARE AND RETURN
if ($a == $b) return 0;
return ($a > $b) ? -1 : 1;
}
// ITERATE OVER THE ARRAY OF ARRAYS OF OBJECTS
foreach ($standings as $t => $type)
{
$new_array = $type["standings"];
usort($new_array, 'cmp');
$standings[$t]["standings"] = $new_array;
}
// SHOW THE REVISED ORDER
var_dump($standings);
$standings['standings'][1]
this is how you access the standing value and not $a['standings']['standing'