2 votes

Aplatissement d'un tableau associatif multidimensionnel en un tableau unidimensionnel de références en PHP

Étant donné que j'ai un tableau :

$array = array(
    'a' => array(
        'b' => array(
            'c' => 'hello',
        ),
    ),
    'd' => array(
        'e' => array(
            'f' => 'world',
        ),
    ),
);

Je veux l'"aplatir" en une consultation de références à une seule dimension, en concaténant les clés avec un délimiteur ( dans le cas de cet exemple, une barre oblique. / )

Effectuer un var_dump() sur une sortie réussie donnerait : ( notez toutes les références )

array(6) {
  ["a"]=>
  &array(1) {
    ["b"]=>
    &array(1) {
      ["c"]=>
      &string(5) "hello"
    }
  }
  ["a/b"]=>
  &array(1) {
    ["c"]=>
    &string(5) "hello"
  }
  ["a/b/c"]=>
  &string(5) "hello"
  ["d"]=>
  &array(1) {
    ["e"]=>
    &array(1) {
      ["f"]=>
      &string(5) "world"
    }
  }
  ["d/e"]=>
  &array(1) {
    ["f"]=>
    &string(5) "world"
  }
  ["d/e/f"]=>
  &string(5) "world"
}
array(2) {
  ["a"]=>
  &array(1) {
    ["b"]=>
    &array(1) {
      ["c"]=>
      &string(5) "hello"
    }
  }
  ["d"]=>
  &array(1) {
    ["e"]=>
    &array(1) {
      ["f"]=>
      &string(5) "world"
    }
  }
}

En l'état actuel des choses, j'utilise ceci :

function build_lookup(&$array, $keys = array()){
    $lookup = array();
    foreach($array as $key => &$value){
        $path = array_merge($keys, (Array) $key);
        $lookup[implode('/', $path)] = &$value;
        if(is_array($value)){
            $lookup = array_merge($lookup, build_lookup($value, $path));
        }
    }
    return $lookup;
}

Cependant, j'essaie de l'améliorer en supprimant l'élément de récursion ( passer à une approche stack/pop ) Le problème de cette méthode est la préservation des références, car l'approche typique de récursion à non-récursion de :

$stack = $input;
while(!empty($stack)){
    $current = array_pop($stack);
    // do stuff and push to stack;
}

...échoue avec les références.

J'ai vu quelques questions/réponses similaires sur SO, mais aucune ne traitait de manière appropriée des références ( car ce n'était pas l'intention de l'auteur de la question. )

Existe-t-il une meilleure ( lire plus vite ) ici ?


La solution éventuelle ( Merci @chris ) :

/**
 *
 * @return array
 */
public function get_lookup_array()
{
    $stack = $lookup = array();
    try
    {
        foreach($this->_array as $key => &$value)
        {
            $stack[$key] = &$value;
        }
        while(!empty($stack))
        {
            $path = key($stack);
            $lookup[$path] = &$stack[$path];
            if(is_array($lookup[$path]))
            {
                foreach($lookup[$path] as $key => &$value)
                {
                    $stack[$path . $this->_separator . $key] = &$value;
                }
            }
            unset($stack[$path]);
        }
    }
    catch(\Exception $exception)
    {
        return false;
    }
    return $lookup;
}

2voto

goat Points 17643
header('content-type:text/plain');

$arr = array(
    'a' => array(
        'b' => array(
            'c' => 'hello',
        ),
    ),
    'd' => array(
        'e' => array(
            'f' => 'world',
        ),
    ),
);

//prime the stack using our format
$stack = array();
foreach ($arr as $k => &$v) {
    $stack[] = array(
        'keyPath' => array($k),
        'node' => &$v
    );
}

$lookup = array();

while ($stack) {
    $frame = array_pop($stack);
    $lookup[join('/', $frame['keyPath'])] = &$frame['node'];
    if (is_array($frame['node'])) {
        foreach ($frame['node'] as $key => &$node) {
            $keyPath = array_merge($frame['keyPath'], array($key));
            $stack[] = array(
                'keyPath' => $keyPath,
                'node' => &$node
            );
            $lookup[join('/', $keyPath)] = &$node;
        }
    }
}

var_dump($lookup);
// check functionality
$lookup['a'] = 0;
$lookup['d/e/f'] = 1;
var_dump($arr);

Alternativement, vous auriez pu faire quelque chose comme ceci pour obtenir une référence /w array_pop functionality

end($stack);
$k = key($stack);
$v = &$stack[$k];
unset($stack[$k]);

Cela fonctionne parce que les tableaux php ont des éléments ordonnés par heure de création de la clé. unset() supprime la clé, et donc réinitialise l'heure de création de cette clé.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X