skip to Main Content

I have two multi-dimensional arrays and need to sort the first array in the same order as the second array based on different keys (but their values are the same). In the below example I need $allOptions to be sorted into the same order as $regOptions but based on the values of clID == optID.

However, not all $allOptions sub-arrays (clID) are present in $regOptions sub-arrays (optID)….so any non-matched elements in $allOptions would be thrown to the bottom/end of the array.

How can I do this?

$allOptions = array(
     array("clID"=> 171, ...other values),
     array("clID"=> 191, ...other values),
     array("clID"=> 131, ...other values),
     array("clID"=> 101, ...other values),
     array("clID"=> 201, ...other values),
     array("clID"=> 181, ...other values),
     ...
     array("clID"=> 99, ...other values),  // not in regOptions
     array("clID"=> 129, ...other values)  // not in regOptions
     array("clID"=> 139, ...other values)
    
) ;

$regOptions = array(
    array("order"=>1,"optID"=> 131, ...other values),
    array("order"=>2,"optID"=> 191, ...other values),
    array("order"=>3,"optID"=> 181, ...other values),
    array("order"=>4,"optID"=> 139, ...other values),
    array("order"=>5,"optID"=> 101, ...other values),
    array("order"=>6,"optID"=> 201, ...other values),
    array("order"=>7,"optID"=> 171, ...other values) 
    ...
) ;

So the output would be:

$allOptions = array(
     array("clID"=> 131, ...other values),
     array("clID"=> 191, ...other values),
     array("clID"=> 181, ...other values),
     array("clID"=> 139, ...other values)
     array("clID"=> 101, ...other values),
     array("clID"=> 201, ...other values),
     array("clID"=> 171, ...other values),
     ...
     array("clID"=> 99, ...other values),  // not in regOptions
     array("clID"=> 129, ...other values)  // not in regOptions
) ;

3

Answers


  1. Use php usort()

    Example

    function customSort($a, $b, $regOptions) {
      $aOptID = $a['clID'];
      $bOptID = $b['clID'];
      $aOrder = array_search($aOptID, array_column($regOptions, 'optID'));
      $bOrder = array_search($bOptID, array_column($regOptions, 'optID'));
      return $aOrder - $bOrder;
    }
    
    usort($allOptions, function($a, $b) use ($regOptions) {
      return customSort($a, $b, $regOptions);
    });
    
    Login or Signup to reply.
  2. Here is a solution not based on array_search():

    $allOptions = [["clID" => 1], ["clID" => 2], ["clID" => 3], ["clID" => 4]];
    $regOptions = [["optID" => 3], ["optID" => 2]];
    
    $order = [];
    foreach($regOptions as $key => $option)
        $order[$option['optID']] = $key;
    
    usort($allOptions, function($o1, $o2) use($order)
    {
        $id1 = $o1['clID'];
        $id2 = $o2['clID'];
        if(isset($order[$id1]) && isset($order[$id2]))
            return $order[$id1] <=> $order[$id2];
        if(isset($order[$id1]) && !isset($order[$id2]))
            return -1;
        if(!isset($order[$id1]) && isset($order[$id2]))
            return 1;
        return $id1 <=> $id2;
    });
    
    var_export($allOptions);
    

    Result:

    array (
      0 => 
      array (
        'clID' => 3,
      ),
      1 => 
      array (
        'clID' => 2,
      ),
      2 => 
      array (
        'clID' => 1,
      ),
      3 => 
      array (
        'clID' => 4,
      ),
    )
    
    Login or Signup to reply.
  3. Another option to sorting would be iterating over $regOptions and building a new array from $allOptions, and then appending any items not found to the end.

    <?php
    
    $allOptions = array(
         array("clID"=> 171),
         array("clID"=> 191),
         array("clID"=> 131),
         array("clID"=> 101),
         array("clID"=> 201),
         array("clID"=> 181),
         array("clID"=> 99),  // not in regOptions
         array("clID"=> 129),  // not in regOptions
         array("clID"=> 139),
    ) ;
    
    $regOptions = array(
        array("order"=>1,"optID"=> 131),
        array("order"=>2,"optID"=> 191),
        array("order"=>3,"optID"=> 181),
        array("order"=>4,"optID"=> 139),
        array("order"=>5,"optID"=> 101),
        array("order"=>6,"optID"=> 201),
        array("order"=>7,"optID"=> 171) 
    );
    
    $newArray = [];
    foreach($regOptions as $order) {
        // get the index of the item in $allOptions
        $searchIndex = array_search($order['optID'], array_column($allOptions, 'clID'), true);
        
        if ($searchIndex === false) {
            continue;
        }
        
        // because we do unset($allOptions[x]) if found, the keys
        // of that array aren't guaranteed to be 0...n anymore. So use 
        // array_keys() to get the real index of the item we found
        $realIndex = array_keys($allOptions)[$searchIndex];
        
        $newArray[] = $allOptions[$realIndex];
        unset($allOptions[$realIndex]);
    }
    
    // var_dump($newArray);
    // var_dump($allOptions);
    
    $final = array_merge($newArray, $allOptions);
    
    var_dump($final);
    

    Output:

    array(9) {
      [0]=> array(1) {
        ["clID"]=> int(131) 
      }
      [1]=> array(1) {
        ["clID"]=> int(191) 
      }
      [2]=> array(1) {
        ["clID"]=> int(181) 
      }
      [3]=> array(1) {
        ["clID"]=> int(139) 
      }
      [4]=> array(1) {
        ["clID"]=> int(101) 
      }
      [5]=> array(1) {
        ["clID"]=> int(201) 
      }
      [6]=> array(1) {
        ["clID"]=> int(171) 
      }
      [7]=> array(1) {
        ["clID"]=> int(99) 
      }
      [8]=> array(1) {
        ["clID"]=> int(129) 
      } 
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search