Skip to content
Advertisement

How to sort an array B (multidimensional) in php by the order of values in an array A (1 dimension)?

The alphabet is a substitute for the same specific character so that it is easy to see.

order case-1

$arr_a = array('C','A','B','D');

order case-2

$arr_a = array('B','A','D','C','E');

Array to be changed

$arr_b = Array 
      ( 
        Array ( 'E','E_val1','E_val2','E_val3' ),
        Array ( 'B','B_val1','B_val2','B_val3' ),
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' )
      )

result by case-1

$arr_b = Array 
      ( 
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' ),
        Array ( 'B','B_val1','B_val2','B_val3' )
      )

or (Anything will be fine.)

$arr_b = Array 
      ( 
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' ),
        Array ( 'B','B_val1','B_val2','B_val3' ),
        Array ( '' )
      )

result by case-2

$arr_b = Array 
      ( 
        Array ( 'B','B_val1','B_val2','B_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' ),
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'E','E_val1','E_val2','E_val3' )
      )

or (Anything will be fine.)

$arr_b = Array 
      ( 
        Array ( 'B','B_val1','B_val2','B_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' ),
        Array ( '' ),
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'E','E_val1','E_val2','E_val3' )
      )

tried code is like this.

//$order is row type from other page.
$arr_a = array();
for ($j=0; $j < count($order); $j++) {
    array_push($arr_a, $order_id[$j]);
}

// so now..) $arr_a = array('C','A','B','D');
// $total_b_arr = array('E^E_val1^E_val2^E_val3','B^B_val1^B_val2^B_val3','C^C_val1^C_val2^C_val3','A^A_val1^A_val2^A_val3')

$arr_b = array();
$z= 0;
foreach( $arr_a as $key => $value ) {
                    
    foreach( $total_b_arr as $key => $value ) {
        ${'each_arr'.$z} = explode("^", trim($total_b_arr[$z]));
        // so now..) ${'each_arr'.$z} = Array( 'E','E_val1','E_val2','E_val3')
        
        if(in_array(${'each_arr'.$z}[0], $arr_a)) {
            array_push($arr_b, ${'each_arr'.$z});
        }
        $z++;
    }
}

//It is necessary to sort here.

//and I have a processing method if we don't put an empty value in the result.

$empty_arr = array();
$z=0;
for ($k=1; $k <= count($arr_a); $k++) {
    list($unique_id, $subj, $type, $val) = $arr_b[$z];
                        
    if($unique_id !== $arr_a[$z]) {
                            
        $arr_front = array_slice($arr_b, 0, $z);
        $arr_end = array_slice($arr_b, $z);
        $arr_front[] = $empty_arr;
                                
        $arr_b = array_merge($arr_front, $arr_end);
                                
        $val = '-';
    }
    $z++;
    
    echo $val;
}

Advertisement

Answer

I would say that a usort would be your best option here, although if it’s not in the context of a custom class, then you’ll have to use global to bring $arr_a into the sorting function.

A note – sorting functions do not REMOVE entries that don’t exist (or at least they shouldn’t ever do that), so I separated it into two steps. The first step is an initial sorting step which sorts/pushes any non-matched entries to the end of the sorted array.

The second step then loops backwards from the end of the sorted $arr_b and removes any entries that weren’t found in the $arr_a array.

<?php
// Source data
$arr_a = array('B','A','D','C','E');

$arr_b = Array 
      ( 
        Array ( 'E','E_val1','E_val2','E_val3' ),
        Array ( 'B','B_val1','B_val2','B_val3' ),
        Array ( 'C','C_val1','C_val2','C_val3' ),
        Array ( 'A','A_val1','A_val2','A_val3' )
      );

// Sort (doesn't remove records not in $arr_a)
usort($arr_b, "kim163_sort");

// Remove any records at the end that aren't in $arr_a
for($i = count($arr_b) - 1; $i >= 0; $i--)
{
  if(!in_array($arr_b[$i][0], $arr_a))
  {
    unset($arr_b[$i]);
    continue;
  }
  break; // By breaking here, we stop checking as soon as there's a match
}

// Show result
print_r($arr_b);

// Custom sorting function
function kim163_sort($a, $b)
{
  global $arr_a;
  $a_pos = array_search($a[0], $arr_a);
  $b_pos = array_search($b[0], $arr_a);
  if($a_pos === $b_pos) { return 0; } 
  if($a_pos === false) { return 1; } // Push values that are not found towards the end
  return ($a_pos < $b_pos) ? -1 : 1;
}

The performance is probably okay if you’re not intending to do this a LOT (e.g. 100,000 times) or if the array is going to always be very small.

If $arr_a is going to have a lot of values, it may be worth doing a few performance optimizations, but what those are depends on what the true values of $arr_a are. If they are truly letters or single characters, you could use join them into a string like $a = “BACD” and use strpos().

Alternatively, do an array_flip() on $arr_a BEFORE the sorting begins and then use array_key_exists() to validate whether the keys exist or not, and then just a regular array access to get the position.

Again, if the arrays are going to be small and/or you’re only doing this a small number of times, then the optimization steps may take up more CPU cycles than whatever savings you’d get from it.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement