2012-06-28 22 views
9

Powiel możliwe:
Converting an array from one to multi-dimensional based on parent ID valuesPHP Tworzenie tablicy wielowymiarowej z tablicy z danymi relacyjnymi

Pracuję w PHP.

Mam następujące tablica, która ma relacyjnych danych (relacje potomka podrzędne).

Array   
(  
    [5273] => Array   
     (  
      [id] => 5273   
      [name] => John Doe   
      [parent] =>   
     )   

    [6032] => Array   
     (  
      [id] => 6032   
      [name] => Sally Smith   
      [parent] => 5273   
     )   

    [6034] => Array   
     (  
      [id] => 6034   
      [name] => Mike Jones   
      [parent] => 6032   
     )   

    [6035] => Array   
     (  
      [id] => 6035   
      [name] => Jason Williams   
      [parent] => 6034   
     )   

    [6036] => Array   
     (  
      [id] => 6036   
      [name] => Sara Johnson   
      [parent] => 5273   
     )   

    [6037] => Array   
     (  
      [id] => 6037   
      [name] => Dave Wilson   
      [parent] => 5273   
     )   

    [6038] => Array   
     (  
      [id] => 6038   
      [name] => Amy Martin   
      [parent] => 6037   
     )   
)   

Muszę go mieć w tym formacie JSON:

{   
    "id":"5273",   
    "name":"John Doe",   
    "data":{   

    },   
    "children":[   
     {   
     "id":" Sally Smith",   
     "name":"6032",   
     "data":{   

     },   
     "children":[   
      {   
       "id":"6034",   
       "name":"Mike Jones",   
       "data":{   

       },   
       "children":[   
        {   
        "id":"6035",   
        "name":"Jason Williams",   
        "data":{   

        },   
        "children":[   
         {   
          "id":"node46",   
          "name":"4.6",   
          "data":{   

          },   
          "children":[   

          ]   
         }   
        ]   
        }   
       ]   
      },   
      {   
       "id":"6036",   
       "name":"Sara Johnson",   
       "data":{   

       },   
       "children":[   

       ]   
      },   
      {   
       "id":"6037",   
       "name":"Dave Wilson",   
       "data":{   

       },   
       "children":[   
        {   
        "id":"6038",   
        "name":"Amy Martin",   
        "data":{   

        },   
        "children":[   

        ]   
        }   
       ]   
      }   
     ]   
     }   
    ]   
}   

wiem, że trzeba utworzyć tablicę wielowymiarową i uruchomić go za pośrednictwem json_encode(). Sądzę też, że metoda używana do tego musi być rekurencyjna, ponieważ dane z rzeczywistego świata mogą mieć nieznaną liczbę poziomów.

Byłbym szczęśliwy pokazując niektóre z moich podejść, ale nie zadziałały.

Czy ktoś może mi pomóc?

Zostałem poproszony o udostępnienie mojej pracy. Tego właśnie próbowałem, ale nie zbliżyłem się tak bardzo, że nie wiem, jak to jest pomocne.

Zrobiłem szereg tylko relacji.

foreach($array as $k => $v){ 
    $relationships[$v['id']] = $v['parent']; 
} 

Myślę, że (w oparciu o inne stanowisko SO) wykorzystał te dane relacyjne do stworzenia nowej wielowymiarowej tablicy. Jeśli mam to do pracy jadę do pracy na dodanie w poprawnych „dzieci” etykiet itp

$childrenTable = array(); 
    $data = array(); 
    foreach ($relationships as $n => $p) { 
     //parent was not seen before, put on root 
     if (!array_key_exists($p, $childrenTable)) { 
      $childrenTable[$p] = array(); 
      $data[$p] = &$childrenTable[$p]; 
     } 
     //child was not seen before 
     if (!array_key_exists($n, $childrenTable)) { 
      $childrenTable[$n] = array(); 
     } 
     //root node has a parent after all, relocate 
     if (array_key_exists($n, $data)) { 
      unset($data[$n]); 
     } 
     $childrenTable[$p][$n] = &$childrenTable[$n];  
    } 
    unset($childrenTable); 

print_r($data); 
+0

Początkowo opublikowany format * to * tablica wielowymiarowa. Czy ta praca nie powinna być kodowana w Json? –

+0

Ben Roux, Tak, jest to tablica wielowymiarowa, ale nie jest w odpowiednim formacie, aby wyprodukować ten JSON. – maestrojed

+0

co próbowałeś? opublikuj swój kod, przygotowując tablicę. – Sanjay

Odpowiedz

12
<?php 
header('Content-Type: application/json; charset="utf-8"'); 

/** 
* Helper function 
* 
* @param array $d flat data, implementing a id/parent id (adjacency list) structure 
* @param mixed $r root id, node to return 
* @param string $pk parent id index 
* @param string $k id index 
* @param string $c children index 
* @return array 
*/ 
function makeRecursive($d, $r = 0, $pk = 'parent', $k = 'id', $c = 'children') { 
    $m = array(); 
    foreach ($d as $e) { 
    isset($m[$e[$pk]]) ?: $m[$e[$pk]] = array(); 
    isset($m[$e[$k]]) ?: $m[$e[$k]] = array(); 
    $m[$e[$pk]][] = array_merge($e, array($c => &$m[$e[$k]])); 
    } 

    return $m[$r][0]; // remove [0] if there could be more than one root nodes 
} 

echo json_encode(makeRecursive(array(
    array('id' => 5273, 'parent' => 0, 'name' => 'John Doe'), 
    array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'), 
    array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'), 
    array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'), 
    array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'), 
    array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'), 
    array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'), 
))); 

demo: https://3v4l.org/s2PNC

+0

Yoshi, dziękuję. Uruchomiłem twój kod przeciwko testowi i działa świetnie. Jednak gdy zaimplementowałem jakieś rzeczywiste dane, może to być 300-400 osób. Dostaję PHP wyczerpane 128 MB błędu pamięci. Rozumiem, że 300-400 rekordów to więcej niż podany przeze mnie przykład, ale nie sądziłem, że będzie to duży zbiór danych. Jakieś pomysły? Czy ma to sens, że korzystało z tak dużej ilości pamięci? – maestrojed

+0

@maestrojed Wystąpił błąd w mojej pierwszej wersji (prawdopodobnie przyczyna wycieku pamięci), proszę spojrzeć na aktualizację. – Yoshi

+1

To działało i było więcej niż się spodziewałem. Dzięki za pomoc. Nie mogę się doczekać, aby to przeanalizować i dowiedzieć się czegoś! – maestrojed

2

poniższy kod zrobi pracy .. może chcesz podkręcić trochę w zależności od potrzeb.

$data = array(
    '5273' => array('id' =>5273, 'name'=> 'John Doe', 'parent'=>''), 
    '6032' => array('id' =>6032, 'name'=> 'Sally Smith', 'parent'=>'5273'), 
    '6034' => array('id' =>6034, 'name'=> 'Mike Jones ', 'parent'=>'6032'), 
    '6035' => array('id' =>6035, 'name'=> 'Jason Williams', 'parent'=>'6034') 
    ); 

$fdata = array(); 


function ConvertToMulti($data) { 
    global $fdata; 

    foreach($data as $k => $v) 
    { 
     if(empty($v['parent'])){ 
      unset($v['parent']); 
     $v['data'] = array(); 
     $v['children'] = array(); 
      $fdata[] = $v; 
     } 
     else { 
      findParentAndInsert($v, $fdata); 
     } 

    } 
} 

function findParentAndInsert($idata, &$ldata) { 

    foreach ($ldata as $k=>$v) { 

     if($ldata[$k]['id'] == $idata['parent']) { 
      unset($idata['parent']); 
     $idata['data'] = array(); 
     $idata['children'] = array(); 
      $ldata[$k]['children'][] = $idata; 
      return; 
     } 
     else if(!empty($v['children'])) 
      findParentAndInsert($idata, $ldata[$k]['children']); 
    } 
} 


print_r($data); 
ConvertToMulti($data); 
echo "AFTER\n"; 
print_r($fdata); 

http://codepad.viper-7.com/Q5Buaz

+0

Mam zamiar próbować tego rano. Przy pierwszym wdrożeniu wydawało się, że ma problemy. Nie jestem pewien co jeszcze i postaram się skomentować z powrotem szczegółami. Kiedy go zaimplementowałem, nie dostaję błędu, a struktura wydaje się odpowiednia, ale brakuje wielu danych. – maestrojed

+0

Zwróć uwagę na kilka rzeczy, po pierwsze, wypełnij tablicę $ data twoją. Nie ma wszystkich wartości użytych w pytaniu. Po drugie, możesz ustawić funkcję $ fdata local na ConvertToMulti. Uczynienie go globalnym może spowodować problem z wdrożeniem. Powodzenia z wdrożeniem – FatalError

3

Dobra, to jak to działa, to rzeczywiście nie jest zbyt daleko, jak to się zaczęło, ale to, co rzeczywiście szukać są referencje. Jest to procedura ogólna:

Ponieważ istnieje relacja między węzłem nadrzędnym a węzłem podrzędnym na ich identyfikatorze, należy najpierw zaindeksować dane na podstawie identyfikatora. Robię to tutaj z tablicą ($rows), aby zasymulować dostęp do danych, jeśli czytasz z bazy danych, byłoby to podobne. Za pomocą tego indeksowania możesz także dodać dodatkowe właściwości, takie jak puste dane:

// create an index on id 
$index = array(); 
foreach($rows as $row) 
{ 
    $row['data'] = (object) array(); 
    $index[$row['id']] = $row; 
} 

Teraz wszystkie wpisy są indeksowane na ich ID. To był pierwszy krok.

Drugi krok jest równie prosty. Ponieważ teraz możemy uzyskać dostęp do każdego węzła na podstawie jego identyfikatora w $index, możemy przypisać dzieci do ich rodziców.

Istnieje jeden "wirtualny" węzeł, czyli ten o identyfikatorze 0.Nie istnieje on w żadnym z wierszy, jednak jeśli możemy dodać do niego również dzieci, możemy użyć tej kolekcji podrzędnej jako magazynu dla wszystkich węzłów root, w twoim przypadku istnieje jeden węzeł główny.

Oczywiście, dla identyfikatora 0 nie powinniśmy przetwarzać elementu nadrzędnego - ponieważ nie istnieje.

Zróbmy to. Wykorzystujemy referencje tutaj, bo w przeciwnym razie sam węzeł nie może być zarówno rodzic i dziecko:

// build the tree 
foreach($index as $id => &$row) 
{ 
    if ($id === 0) continue; 
    $parent = $row['parent']; 
    $index[$parent]['children'][] = &$row; 
} 
unset($row); 

Ponieważ używamy referencje, ostatnia linia dba aby rozbroić odniesienia przechowywanej w $row po pętli.

Teraz wszystkie dzieci zostały przydzielone do rodziców. To może już być, ale nie zapominajmy o ostatnim kroku, dostęp do bieżącego węzła dla wyjścia.

Dla zwięzłości wystarczy przypisać węzeł główny do samego $index. Jeśli pamiętamy, tylko węzeł główny chcemy to pierwsza w tablicy Dzieci w węźle z ID 0:

// obtain root node 
$index = $index[0]['children'][0]; 

I to wszystko. Możemy go używać teraz od razu wygenerować JSON:

// output json 
header('Content-Type: application/json'); 
echo json_encode($index); 

Wreszcie cały kod w skrócie:

<?php 
/** 
* @link http://stackoverflow.com/questions/11239652/php-create-a-multidimensional-array-from-an-array-with-relational-data 
*/ 

$rows = array(
    array('id' => 5273, 'parent' => 0, 'name' => 'John Doe'), 
    array('id' => 6032, 'parent' => 5273, 'name' => 'Sally Smith'), 
    array('id' => 6034, 'parent' => 6032, 'name' => 'Mike Jones'), 
    array('id' => 6035, 'parent' => 6034, 'name' => 'Jason Williams'), 
    array('id' => 6036, 'parent' => 5273, 'name' => 'Sara Johnson'), 
    array('id' => 6037, 'parent' => 5273, 'name' => 'Dave Wilson'), 
    array('id' => 6038, 'parent' => 6037, 'name' => 'Amy Martin'), 
); 

// create an index on id 
$index = array(); 
foreach($rows as $row) 
{ 
    $row['data'] = (object) []; 
    $index[$row['id']] = $row; 
} 

// build the tree 
foreach($index as $id => &$row) 
{ 
    if ($id === 0) continue; 
    $parent = $row['parent']; 
    $index[$parent]['children'][] = &$row; 
} 
unset($row); 

// obtain root node 
$index = $index[0]['children'][0]; 

// output json 
header('Content-Type: application/json'); 
echo json_encode($index, JSON_PRETTY_PRINT); 

mogących spowodować następujący json (tutaj z PHP 5.4s' JSON_PRETTY_PRINT):

{ 
    "id": 5273, 
    "parent": 0, 
    "name": "John Doe", 
    "data": { 

    }, 
    "children": [ 
     { 
      "id": 6032, 
      "parent": 5273, 
      "name": "Sally Smith", 
      "data": { 

      }, 
      "children": [ 
       { 
        "id": 6034, 
        "parent": 6032, 
        "name": "Mike Jones", 
        "data": { 

        }, 
        "children": [ 
         { 
          "id": 6035, 
          "parent": 6034, 
          "name": "Jason Williams", 
          "data": { 

          } 
         } 
        ] 
       } 
      ] 
     }, 
     { 
      "id": 6036, 
      "parent": 5273, 
      "name": "Sara Johnson", 
      "data": { 

      } 
     }, 
     { 
      "id": 6037, 
      "parent": 5273, 
      "name": "Dave Wilson", 
      "data": { 

      }, 
      "children": [ 
       { 
        "id": 6038, 
        "parent": 6037, 
        "name": "Amy Martin", 
        "data": { 

        } 
       } 
      ] 
     } 
    ] 
} 
+0

Czy możesz wyjaśnić, co nie jest ustawione ($ row); robi –

+0

@LovepreetSinghBatth: To jest "Ponieważ używamy referencji, ostatnia linia dba o usunięcie referencji przechowywanej w $ row po pętli." poniżej przykładu, w którym jest. – hakre

Powiązane problemy