Преобразовать плоский массив PHP в вложенный массив на основе ключей массива? - PullRequest
10 голосов
/ 19 августа 2011

Мне нужно преобразовать плоский массив, где ключи массива указывают структуру, во вложенный массив, где родительский элемент становится нулевым элементом, т.е. в примере:

$education['x[1]'] = 'Georgia Tech';

Необходимо преобразовать в:

$education[1][0] = 'Georgia Tech';

Вот пример входного массива:

$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);

А вот что должно быть на выходе:

$education => array(
  1 => array(
    0 => 'Georgia Tech',
    1 => array( 0 => 'Mechanical Engineering' ),
    2 => array( 0 => 'Computer Science' ),
  ),
  2 => array(
    0 => 'Agnes Scott',
    1 => array( 0 => 'Religious History' ),
    2 => array( 0 => 'Women\'s Studies' ),
  ),
  3 => array(
    0 => 'Georgia State',
    1 => array( 0 => 'Business Administration' ),
  ),
);

Я часами бился головой о стену и до сих пор не могу заставить ее работать. Я думаю, что смотрю на это слишком долго. Заранее спасибо.

P.S. Он должен быть полностью вложенным, то есть иметь возможность преобразовывать ключ, который выглядит следующим образом:

x[1][2][3][4][5][6] 

P.P.S. У @Joseph Silber было умное решение, но, к сожалению, использование eval() не подходит для этого, так как это плагин WordPress, а сообщество WordPress пытается исключить использование eval().

Ответы [ 6 ]

4 голосов
/ 19 августа 2011

Вот некоторый код для обработки того, что вы изначально предложили в качестве вывода.

/**
 * Give it and array, and an array of parents, it will decent into the
 * nested arrays and set the value.
 */
function set_nested_value(array &$arr, array $ancestors, $value) {
  $current = &$arr;
  foreach ($ancestors as $key) {

    // To handle the original input, if an item is not an array, 
    // replace it with an array with the value as the first item.
    if (!is_array($current)) {
      $current = array( $current);
    }

    if (!array_key_exists($key, $current)) {
      $current[$key] = array();
    }
    $current = &$current[$key];
  }

  $current = $value;
}


$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);

$neweducation = array();

foreach ($education as $path => $value) {
  $ancestors = explode('][', substr($path, 2, -1));
  set_nested_value($neweducation, $ancestors, $value);
}

По сути, разделите ваши ключи массива на хороший массив ключей-предков, затем используйте хорошую функцию для преобразования в массив $ neweducation с помощью этих родителей и установите значение.

Если вы хотите, чтобы вывод, который вы обновили в своем посте, был добавлен, добавьте его в цикл foreach после строки 'explode'.

$ancestors[] = 0;
3 голосов
/ 19 августа 2011
$result = array();

foreach( $education as $path => $value ) {

    $parts = explode('][', trim( $path, 'x[]' ) );
    $target =& $result;

    foreach( $parts as $part )
        $target =& $target[$part];

    $target = array($value);
}

var_dump($result);
2 голосов
/ 19 августа 2011
<?php
$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);
$x = array();
foreach ($education as $key => $value) {
        parse_str($key . '[0]=' . urlencode($value));
}
var_dump($x);
1 голос
/ 19 августа 2011
$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women\'s Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
  // Uncomment to test deep nesting.
  // 'x[1][2][3][4][5][6] ' => 'Underwater Basket Weaving',
);

$newarray = array();
foreach ($education as $key => $value) {

  // Parse out the parts of the key and convert them to integers.
  $parts = explode('[', $key);
  for($i = 1; $i < count($parts); $i += 1) {
    $parts[$i] = intval(substr($parts[$i], 0, 1));
  }

  // Walk the parts, creating subarrays as we go.
  $node = &$new_array;
  for($i = 1; $i < count($parts); $i += 1) {
    // Create subarray if it doesn't exist.
    if (!isset($node[$parts[$i]])) {
      $node[$parts[$i]] = array();
    }
    // Step down to the next dimension.
    $node = &$node[$parts[$i]];
  }
  // Insert value.
  $node[0] = $value;
}
$education = $new_array;

var_dump($education);

ОБНОВЛЕНИЕ: Модифицированное решение для соответствия новым требованиям.ОБНОВЛЕНИЕ: убраны имена переменных и добавлены комментарии.(Последнее редактирование, я обещаю:))

0 голосов
/ 20 июля 2016

Основываясь на первом предложении выше Я нашел решение, которое работало для моего файла .ini, изменив переменную $ ancestors.

РЕДАКТИРОВАТЬ: Вот полная версия моего рабочего кода: https://stackoverflow.com/a/38480646/1215633

//$ancestors = explode('][', substr($path, 2, -1));
$ancestors = explode('.', $path);

У меня была эта настройка в моем массиве на основе файла .ini:

[resources.db.adapter] => PDO_MYSQL
[resources.db.params.host] => localhost
[resources.db.params.dbname] => qwer
[resources.db.params.username] => asdf
[resources.db.params.password] => zxcv
[resources.db.params.charset] => utf8
[externaldb.adapter] => PDO_MYSQL
[externaldb.params.host] => localhost
[externaldb.params.dbname] => tyui
[externaldb.params.username] => ghjk
[externaldb.params.password] => vbnm
[externaldb.params.charset] => latin1

Результат стал таким, как хотелось:

Array
(
[resources] => Array
    (
        [db] => Array
            (
                [adapter] => PDO_MYSQL
                [params] => Array
                    (
                        [host] => localhost
                        [dbname] => qwer
                        [username] => asdf
                        [password] => zxcv
                        [charset] => utf8
                    )

            )

    )

[externaldb] => Array
    (
        [adapter] => PDO_MYSQL
        [params] => Array
            (
                [host] => localhost
                [dbname] => tyui
                [username] => ghjk
                [password] => vbnm
                [charset] => latin1
            )

    )

)
0 голосов
/ 19 августа 2011

Если вы также всегда будете хранить первый элемент в массиве с [0], то вы можете использовать это:

$education = array(
    'x[1][0]' => 'Georgia Tech',
    'x[1][1]' => 'Mechanical Engineering',
    'x[1][2]' => 'Computer Science',
    'x[2][0]' => 'Agnes Scott',
    'x[2][1]' => 'Religious History',
    'x[2][2]' => 'Women\'s Studies',
    'x[3][0]' => 'Georgia State',
    'x[3][1]' => 'Business Administration'
);

$x = array();

foreach ($education as $key => $val)
{
    eval('$'.$key.'=$val;');
}

print_r($x);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...