Преобразовать массив в дерево

291
13 февраля 2017, 17:18

Добрый день. Получаю при помощи mysqli_fetch_assoc массив такого формата

array(4) {     
array(5) {["cat"]=> "guest" , ["name"]=> "name_one" , ["y"]=> "2016", ["q"]=> "2", ["st"]=>  "1"}     
array(5) {["cat"]=> "guest" , ["name"]=> "name_one" , ["y"]=> "2017", ["q"]=> "3", ["st"]=>  "2"}     
array(5) {["cat"]=> "guest" , ["name"]=> "name_two" , ["y"]=> "2017", ["q"]=> "1", ["st"]=>  "1"}     
array(5) {["cat"]=> "guest" , ["name"]=> "name_two" , ["y"]=> "2017", ["q"]=> "2", ["st"]=>  "2"} 
} 

Как на PHP преобразовать его в такое дерево

  {["cat"]=> "guest"{
        ["name"]=> "name_one"{
            ["y"]=> "2016"{
                ["q"]=> "2", 
                ["st"]=>"1"
            }
            ["y"]=> "2017"{
                ["q"]=> "3", 
                ["st"]=>"2"
            }
        }
        ["name"]=> "name_two"{
            ["y"]=> "2016"{
                ["q"]=> "2", 
                ["st"]=>"1"
            }
            ["y"]=> "2017"{
                ["q"]=> "3", 
                ["st"]=>"2"
            }
        }
    }
}
Answer 1

Насколько мне известен контекст вашей задачи, вам лучше не сохранять ключи в структуре(name, y...):

Fiddle

$rows = [
  ['cat' => 'guest', 'name' => 'name_one', 'y' => '2016', 'q' => '2', 'st' => 1],
  ['cat' => 'guest', 'name' => 'name_one', 'y' => '2017', 'q' => '3', 'st' => 2],
  ['cat' => 'guest', 'name' => 'name_two', 'y' => '2017', 'q' => '1', 'st' => 1],
  ['cat' => 'guest', 'name' => 'name_two', 'y' => '2017', 'q' => '2', 'st' => 2],
];
$data = [];
foreach ($rows as $row) {
  $link = &$data;
  foreach (['cat', 'name', 'y'] as $field) {
      if (!isset($link[$row[$field]])) $link[$row[$field]] = [];
      $link = &$link[$row[$field]];
  }
  $link[$row['q']] = $row['st'];
  unset($link);
}
print_r($data);

Полный ответ к связанному вопросу

Если же вам необходимо сохранить ключи, придётся ввести лишний уровень для отделения значений текущего уровня от списка потомков:

Fiddle

$data = [];
foreach ($rows as $row) {
  $link = &$data;
  foreach (['cat', 'name', 'y'] as $field) {
      if (!isset($link[$field])) $link[$field] = [];
      if (!isset($link[$field][$row[$field]])) $link[$field][$row[$field]] = [];
      $link = &$link[$field][$row[$field]];
  }
  $link[] = ['q' => $row['q'], 'st' => $row['st']];
  unset($link);
}
echo json_encode($data);

Результат:

{
  "cat":{
    "guest":{
      "name":{
        "name_one":{
          "y":{
            "2016":[{"q":"2","st":1}],
            "2017":[{"q":"3","st":2}]
          }
        },
        "name_two":{
          "y":{
            "2017":[{"q":"1","st":1},{"q":"2","st":2}]}}}}}}
Answer 2

Массив надо получать не с помощью mysqli, а с помощью PDO.

Тогда ничего перестраивать не придется, PDO все сделает за нас.

$stmt = $pdo->query("SELECT name, y, q, st FROM table");
$data = $stmt->fetchAll(PDO:FETCH_GROUP);

вернет нам массив уже сгруппированный по name.

Answer 3

Если я Вас правильно понял, то можно попробовать такой способ, который отделяет ключи:

<?php
$assoc = array(
    array(
        "cat"  => "guest1",
        "name" => "name_one1",
        "y"    => "2000",
        "q"    => "my1",
        "st"   => 1
    ), 
    array(
        "cat"  => "guest2",
        "name" => "name_one2",
        "y"    => "2001",
        "q"    => "my2",
        "st"   => 2
    ), 
);
$three = array();
for ($i = 0; $i < count($assoc); $i++) { 
    foreach ($assoc[$i] as $key => $value) {
        $three[$key][] = $value;
    }
}
print_r($three);
?>
READ ALSO
Проверка файлов .txt с помощью getimagesize()

Проверка файлов .txt с помощью getimagesize()

Проверяю загружаемые пользователями thumb картинки с помощью getimagesize() Вот таким образом:

344
$_SERVER[&#39;QUERY_STRING&#39;]

$_SERVER['QUERY_STRING']

Подскажите если сделать запрос например indexphp?root файл index

253
Как добавить значение переменной в (mkdir)

Как добавить значение переменной в (mkdir)

Как добавить значение переменной $sot в mkdir

245
Laravel – перебор внутри контроллера с привязкой к модели

Laravel – перебор внутри контроллера с привязкой к модели

Пытаюсь вывести информацию из базы данных и привязать к ней изображения – хочу следовать шаблону mvc

319