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
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
                        )
 
                )
 
        )
 
)

Open in new window


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;
    }

Open in new window


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!
NarusegawaAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

andreizzCommented:
$standings['standings'][0]['standing']
$standings['standings'][1]['standing']
this is how you access the standing value and not $a['standings']['standing'] cause this is a array
0
andreizzCommented:
you should use something like this:
    foreach($standings)
                 usort($standings['standings'], 'standingStandingSort');

    function standingStandingSort($a, $b) {
        if ($a['standing'] < $b['standings'])
            return 0;
        return ($a['standings'] < $b['standings']) ? -1 : 1;
    }

Open in new window


i am not sure that i got it right, you should double check. this will sort each on in turn.
0
NarusegawaAuthor Commented:
I think I've been a little silly. I just realized that it's an Array of Objects.

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;
    }

Open in new window


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
                )
)

Open in new window


I tried your suggestion, but then I got told that I can't do that with an Object.
0
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

andreizzCommented:
    
    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;
    }

Open in new window


this should work
0
NarusegawaAuthor Commented:
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
if ($a['standing'] < $b['standing'])

Open in new window

0
andreizzCommented:
hang on a second, i am copying the array and trying it myself, faster this way
0
NarusegawaAuthor Commented:
Thanks, I really appreciate the help. I knew mixing objects and arrays was gonna be a pain.
0
Ray PaseurCommented:
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()
0
andreizzCommented:
<?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);
?>

Open in new window


there you have it :D
0
Ray PaseurCommented:
@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.
0
andreizzCommented:
I think what i have posted is exactly what he wanted, let's wait for his answer.
0
Ray PaseurCommented:
Sure.  Look at the example posted here: ID:34932897 -- that would seem to require OOP notation.
0
NarusegawaAuthor Commented:
I'm just trying to get some code together that'd provide the same data structure that I am working with.
0
andreizzCommented:
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);

Open in new window

0
NarusegawaAuthor Commented:
I'll just test that now andreizz.

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 );

?>

Open in new window


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
                        )
 
                )
 
        )
 
)

Open in new window


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
                        )
                 )
 
        )
 
)

Open in new window

0
andreizzCommented:
the above script should work if you just paste it in your php script
0
NarusegawaAuthor Commented:
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['standing'])

Which is the second line in your function :(
0
andreizzCommented:
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.
0
andreizzCommented:
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');
}

Open in new window


i didn't know that was an object of that type i thought it was an array. this works :D
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
NarusegawaAuthor Commented:
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!
0
andreizzCommented:
No problem :D anytime :D

Thanks to you i now have a premium account! :D
0
Ray PaseurCommented:
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);

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
PHP

From novice to tech pro — start learning today.