Home > Mobile >  How to build grouped tree array from flat array in php
How to build grouped tree array from flat array in php

Time:02-10

i am trying to re format a array as tree, main array and child arrays should be grouped by "name" property.

my flat array is like

$flat = [
    ['id' => 1, 'parent_id' => 0, 'name' => 'root1'],
    ['id' => 2, 'parent_id' => 0, 'name' => 'root1'],
    ['id' => 3, 'parent_id' => 1, 'name' => 'ch-1'],
    ['id' => 4, 'parent_id' => 1, 'name' => 'ch-1'],
    ['id' => 5, 'parent_id' => 3, 'name' => 'ch-1-1'],
    ['id' => 6, 'parent_id' => 3, 'name' => 'ch-1-1'],
    ['id' => 7, 'parent_id' => 0, 'name' => 'root2'],
    ['id' => 8, 'parent_id' => 0, 'name' => 'root2'],
    ['id' => 9, 'parent_id' => 7, 'name' => 'ch3-1'],
    ['id' => 10, 'parent_id' => 7, 'name' => 'ch3-1']
];

i could build tree structure by

$tree = buildTree($flat, 'parent_id', 'id');

function buildTree(array $flatList)
{
    $grouped = [];
    foreach ($flatList as $node) {
        $grouped[$node['parent_id']][] = $node;
    }

    $fnBuilder = function ($siblings) use (&$fnBuilder, $grouped) {
        foreach ($siblings as $k => $sibling) {
            $id = $sibling['id'];
            if (isset($grouped[$id])) {
                $sibling['children'] = $fnBuilder($grouped[$id]);
            }
            $siblings[$k] = $sibling;
        }
        return $siblings;
    };

    return $fnBuilder($grouped[0]);
}

this works perfectly.

But what i want is build nested array should be grouped by it's "name" property.

so the final output should be like

[
  "root1": [{
      "id": 1,
      "parent_id": 0,
      "name": "root1",
      "children": [
        "ch-1": [{
            "id": 3,
            "parent_id": 1,
            "name": "ch-1",
            "children": [
              "ch-1-1": [{
                  "id": 5,
                  "parent_id": 3,
                  "name": "ch-1-1"
                },
                {
                  "id": 6,
                  "parent_id": 3,
                  "name": "ch-1-1"
                }
              ]
            ]
          },
          {
            "id": 4,
            "parent_id": 1,
            "name": "ch-1"
          }
        ]
      ]
    },
    {
      "id": 2,
      "parent_id": 0,
      "name": "root1"
    }
  ],
  "root2": [{
      "id": 7,
      "parent_id": 0,
      "name": "root2",
      "children": [
        "ch3-1": [{
            "id": 9,
            "parent_id": 7,
            "name": "ch3-1"
          },
          {
            "id": 10,
            "parent_id": 7,
            "name": "ch3-2"
          }
        ]
      ]
    },
    {
      "id": 8,
      "parent_id": 0,
      "name": "root2"
    }
  ]
]

I have been stuck here almost for couple of days. Please help me to solve this problem. Thank you.

CodePudding user response:

Use a function like these with unset()

function buildTree(array &$flat, $parentId = 0) {
    $branch = array();

    foreach ($flat as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($flat, $element['id']);
        if ($children) {
            $element['children'] = $children;
        }
        $branch[$element['id']] = $element;
        unset($flat[$element['id']]);
        }
    }
    return $branch;
}

After buildTree we need to group by name here is my code:-

$result = array();
foreach ($buildTree as $element) {
    $result[$element['name']][] = $element;
}

Hope it will help you. see details from here

Thanks

CodePudding user response:

function buildTree(array &$flat, $parentId = 0)
{
    $branch = array();

    foreach ($flat as $element) {
        if ($element['parent_id'] == $parentId) {
            $children = buildTree($flat, $element['id']);
            if ($children) {
                $element['children'] = $children;
            }
            $branch[$element['id']] = $element;
            unset($flat[$element['id']]);
        }
    }
    return $branch;
}

$tree = buildTree($flat, 'name', 'parent_id');

pass tree structure array to groupedTree();

$groupd = groupedTree($tree);

echo json_encode($groupd, JSON_PRETTY_PRINT);


function groupedTree(array &$tree, $parentId = 0)
{
    $result = array();
    foreach ($tree as $element) {
        if (is_array($element) && isset($element['children'])) {
            $a = groupedTree($element['children'], $element['children']);
            $result[$element['name']][] = $a;
        } else {
            $result[$element['name']][] = $element;
        }
    }

    return $result;
}

CodePudding user response:

function buildTree2(array $flatList)
{
    $groupedchildren = [];
    $groupedparents = [];
    foreach ($flatList as $node) {
        if($node['parent_id'] == 0){
            $groupedparents[$node['parent_id']][] = $node;
        }else{
            $groupedchildren[$node['parent_id']][] = $node;
        }
    }
    
    $namegroupedparents = [];
    foreach ($groupedparents as $parent_group) {
        foreach ($parent_group as $node) {
            $namegroupedparents[$node['name']][] = $node;
        }
    }
    
    $namegroupedchildren = [];
    foreach ($groupedchildren as $children_group) {
        foreach ($children_group as $node) {
            $namegroupedchildren[$node['name']][] = $node;
        }
    }
    
    $fnBuilder = function (&$namegroupedparents) use (&$fnBuilder, $namegroupedchildren) {
        foreach($namegroupedparents as &$named){
            foreach($named as &$parentgroup){
                $id = $parentgroup['id'];
                foreach($namegroupedchildren as $thename => $namedall){
                    foreach($namedall as $childgroup){
                        if($childgroup['parent_id'] == $id){
                            if(isset($parentgroup['children'])){
                                if(!in_array($childgroup, $parentgroup['children'][$thename])){
                                    $parentgroup['children'][$thename][] = $childgroup;
                                }
                            }else{
                                $parentgroup['children'][$thename][] = $childgroup;
                            }
                            $fnBuilder($parentgroup['children']);
                        }
                    }
                }
            }
        } 
        return;
    };

    $fnBuilder($namegroupedparents);
    
    return $namegroupedparents;
}

This is working for your current array, but I don't know if it is going to work with different input.

It groups by parent_id then by name while putting the 0 parents in a different array than the rest of the children. Then it builds the children array by recursion.

  • Related