Darkwing
Darkwing

Reputation: 160

How to sort multidim array according to a multidim array in php?

I’m almost going out of my mind – I hope you can help; maybe it’s simple but I’m really stuck right now.

I have the following unordered array of arrays:

$variations_excerpt =
Array ( [4288] => Array ( [pa_farbe] => white-default [pa_groesse] => xl ) 
         [128] => Array ( [pa_farbe] => black-default [pa_groesse] => s )
         [130] => Array ( [pa_farbe] => black-default [pa_groesse] => xxl )
        [4289] => Array ( [pa_farbe] => white-default [pa_groesse] => xxl )
         [127] => Array ( [pa_farbe] => black-default [pa_groesse] => m ) 
         [129] => Array ( [pa_farbe] => black-default [pa_groesse] => xl ) 
        [4286] => Array ( [pa_farbe] => [pa_groesse] => )
         [149] => Array ( [pa_farbe] => black-default [pa_groesse] => l )
        [4287] => Array ( [pa_farbe] => white-default [pa_groesse] => s )
         [126] => Array ( [pa_farbe] => black-default [pa_groesse] => l )
        [4290] => Array ( [pa_farbe] => white-default [pa_groesse] => ) )

(I don’t want to emphasize this, but note that there are empty values (='') sprinkled around in it. It’s meant to be that way.)

Another note: in some odd situations there is a chance that doublettes do exist. In this example one does exist:

...
[126] => Array ( [pa_farbe] => black-default [pa_groesse] => l )
...
[149] => Array ( [pa_farbe] => black-default [pa_groesse] => l ) 
...

I think it’s important to answer the 'doublette question' in advance. ;)

Now, this unordered array above needs to be sorted according to the following array, providing the desired order of all the values. I already managed to make this:

$unique_attribute_values = 
Array ( [pa_farbe] => Array ( [0] => black-default [1] => white-default [2] => ) 
      [pa_groesse] => Array ( [5] => s [6] => m [7] => l [8] => xl [9] => xxl [10] => ) ) 

(The empty values (='') are shifted towards the end.)

Additionally I already know, how many 'dimensions' such an array will have and what are the 'names' of them, the attributes:

$dim = 0;
$dim_names = array();
foreach ($unique_attribute_values as $attr => $val) {
    $dim++;
    $dim_names[$dim] = $attr; 
    }

… resulting in:

$dim = 2;
$dim_names = Array ( [1] => pa_farbe 
                     [2] => pa_groesse ) 

Please note: the 'dimensionality' in this example is 2 – but the dimensionality can vary from 1 to n (with n in praxis almost always < 4). But since it’s kind of unknown, I thought it’s a good idea to determine the dimensionality and have the names (=keys) available, maybe for a future for-loop. (?)

Anyway, the result I need to achieve is the following:

$ordered_excerpt = 
Array ( [128] => Array ( [pa_farbe] => black-default [pa_groesse] => s ) 
        [127] => Array ( [pa_farbe] => black-default [pa_groesse] => m )
        [126] => Array ( [pa_farbe] => black-default [pa_groesse] => l )
        [149] => Array ( [pa_farbe] => black-default [pa_groesse] => l )
        [129] => Array ( [pa_farbe] => black-default [pa_groesse] => xl ) 
        [130] => Array ( [pa_farbe] => black-default [pa_groesse] => xxl )
       [4287] => Array ( [pa_farbe] => white-default [pa_groesse] => s )
       [4288] => Array ( [pa_farbe] => white-default [pa_groesse] => xl ) 
       [4289] => Array ( [pa_farbe] => white-default [pa_groesse] => xxl ) 
       [4290] => Array ( [pa_farbe] => white-default [pa_groesse] => )
       [4286] => Array ( [pa_farbe] => [pa_groesse] => ) ) 

Note that the doublette is on its right place too: [126] and [149].

How would you do it? I appreciate any suggestions!

Thank you very much in advance!

Upvotes: 0

Views: 75

Answers (1)

Ayush Chaudhary
Ayush Chaudhary

Reputation: 716

You have 2 options here: Use uasort or uksort. If you use uasort, the issue you'll face is incase of duplicates. From your expected output, it seems that if the arrays are same, they should ordered by their keys. In uasort compare function you won't have access to those keys.

So you'll have to use uksort and use the key to index into the variations_excerpt array and compare the two values. The compare function is relatively simple as we have the distinct dimensions and the unique_attribute_values array.

Here's the code:

<?php
$variations_excerpt =
array ( 4288 => array ( 'pa_farbe' => 'white-default', 'pa_groesse' => 'xl' ) ,
         128 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 's' ),
         130 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 'xxl' ),
        4289 => array ( 'pa_farbe' => 'white-default', 'pa_groesse' => 'xxl' ),
         127 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 'm' ) ,
         129 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 'xl' ) ,
        4286 => array ( 'pa_farbe' => '',   'pa_groesse' => ''),
         149 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 'l' ),
        4287 => array ( 'pa_farbe' => 'white-default', 'pa_groesse' => 's' ),
         126 => array ( 'pa_farbe' => 'black-default', 'pa_groesse' => 'l' ),
        4290 => array ( 'pa_farbe' => 'white-default', 'pa_groesse' => '' ) 
        );

$dummy = $variations_excerpt;

$unique_attribute_values = 
array ( 
    'pa_farbe' => array ( 
        0 => 'black-default', 
        1 => 'white-default', 
        2 => '' 
    ), 
     'pa_groesse' => array ( 
        5 => 's', 
        6 => 'm', 
        7 => 'l', 
        8 => 'xl', 
        9 => 'xxl', 
        10 => ''
      )
    );
$dim_names = array('pa_farbe', 'pa_groesse');
uksort($variations_excerpt, "cmp");

function cmp($a, $b) {
    global $dim_names, $unique_attribute_values, $dummy;
    foreach($dim_names as $d) {
        $x = array_search($dummy[$a][$d], $unique_attribute_values[$d]);
        $y = array_search($dummy[$b][$d], $unique_attribute_values[$d]);
        if ($x < $y) {
            return -1;
        } else if ($x > $y) {
            return 1;
        }
    }
    if ($a < $b)
        return -1;
    else
        return 1;
}

print_r($variations_excerpt);

?>

Hope it helps.

Note: Possible issues as pointed out by the OP:

(1) One needs to define the 'cmp' function before it is called in uksort(). Alternatively, one can make use of an anonymous function insinde of uksort().

(2) One needs to initialize the global variables used in 'cmp' function scope also outside of this scope als 'global' first.

Upvotes: 1

Related Questions