kobu agency 67l18r4tw w unsplash 2

In PHP there is function array_combine(). This function may not work as expected in the case if a key is met more than once. For this reason, I created the following function:

function array_combine_array($keyname, $array) {
  $ret = array();
  foreach($array as $value) {
    $key = $value[$keyname];
    if(!isset($ret[$key])) $ret[$key] = array();
    array_push($ret[$key], $value);
  }
  return $ret;
}

This function behaves like array_combine() but in its result to every key corresponds an array of values not single value, and this array has exactly the number of elements equal to the number of key occurrences.

To make a step forward, I create a function array_combine_multilevel() which, given an array of associative arrays and an array of keys, creates a multi-level associative array indexed by values of these keys (the first key in the list becomes the outer key in the output associative array, the next key becomes an index in the enclosed array, etc.)

To understand this see the example:

print_r(array_combine_multilevel(array('a', 'b'),
                                 array(array('a'=>1, 'b'=>2, 'c'=>5), array('a'=>1, 'b'=>2, 'c'=>6), array('a'=>3, 'b'=>4, 'c'=>7))));

outputs:

Array
(
    [1] => Array
        (
            [2] => Array
                (
                    [0] => Array
                        (
                            [a] => 1
                            [b] => 2
                            [c] => 5
                        )

                    [1] => Array
                        (
                            [a] => 1
                            [b] => 2
                            [c] => 6
                        )

                )

        )

    [3] => Array
        (
            [4] => Array
                (
                    [0] => Array
                        (
                            [a] => 3
                            [b] => 4
                            [c] => 7
                        )

                )

        )

)

The code for the function array_combine_multilevel():

abstract class FixedDepthTreeTraverser {
  public function traverse(&$tree, $depth) {
    if($depth == 0)
      $this->on_leaf($tree);
    else
      foreach($tree as &$node)
        $this->traverse($node, $depth-1);
  }
  
  abstract protected function on_leaf(&$node);
}

class ArrayCombineTraverser extends FixedDepthTreeTraverser {
  private $keyname;
  
  public function __construct($keyname) {
    $this->keyname = $keyname;
  }
  
  protected function on_leaf(&$node) {
    $node = array_combine_array($this->keyname, $node);
  }
}

// if $keynames == array('a', 'b') then it generates a hash like array('a'=>array('b'=>...))
function array_combine_multilevel($keynames, $array) {
  if(!is_array($keynames)) $keynames = array($keynames);
  $ret = $array;
  for($i=0; $i<count($keynames); ++$i) {
    $keyname = $keynames[$i];
    $worker = new ArrayCombineTraverser($keyname);
    $worker->traverse($ret, $i);
  }
  return $ret;
}
Tags: