Solved

USort with Multi Lveel Array

Posted on 2011-02-19
22
389 Views
Last Modified: 2012-05-11
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!
0
Comment
Question by:Narusegawa
  • 11
  • 7
  • 4
22 Comments
 
LVL 4

Expert Comment

by:andreizz
ID: 34932853
$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
 
LVL 4

Expert Comment

by:andreizz
ID: 34932866
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
 

Author Comment

by:Narusegawa
ID: 34932897
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933013
    
    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
 

Author Comment

by:Narusegawa
ID: 34933029
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933044
hang on a second, i am copying the array and trying it myself, faster this way
0
 

Author Comment

by:Narusegawa
ID: 34933046
Thanks, I really appreciate the help. I knew mixing objects and arrays was gonna be a pain.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 34933105
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933124
<?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
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 34933179
@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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933190
I think what i have posted is exactly what he wanted, let's wait for his answer.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 108

Expert Comment

by:Ray Paseur
ID: 34933201
Sure.  Look at the example posted here: ID:34932897 -- that would seem to require OOP notation.
0
 

Author Comment

by:Narusegawa
ID: 34933208
I'm just trying to get some code together that'd provide the same data structure that I am working with.
0
 
LVL 4

Expert Comment

by:andreizz
ID: 34933218
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
 

Author Comment

by:Narusegawa
ID: 34933235
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933236
the above script should work if you just paste it in your php script
0
 

Author Comment

by:Narusegawa
ID: 34933246
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933252
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
 
LVL 4

Accepted Solution

by:
andreizz earned 500 total points
ID: 34933317
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
 

Author Closing Comment

by:Narusegawa
ID: 34933354
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
 
LVL 4

Expert Comment

by:andreizz
ID: 34933364
No problem :D anytime :D

Thanks to you i now have a premium account! :D
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 34933599
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

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

Part of the Global Positioning System A geocode (https://developers.google.com/maps/documentation/geocoding/) is the major subset of a GPS coordinate (http://en.wikipedia.org/wiki/Global_Positioning_System), the other parts being the altitude and t…
These days socially coordinated efforts have turned into a critical requirement for enterprises.
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
This tutorial will teach you the core code needed to finalize the addition of a watermark to your image. The viewer will use a small PHP class to learn and create a watermark.

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now