Как многомерный массив из древовидного комментария преобразовать в двумерный массив с одним родительским комментарием

Рейтинг: 0Ответов: 1Опубликовано: 29.04.2023

Допустим есть такой массив из комментариев с id и parent_id как ключ к его родительскому комментарию.

$comments = array(
    array('id' => 1, 'text' => 'Комментарий 1', 'parent_id' => null),
    array('id' => 2, 'text' => 'Комментарий 2', 'parent_id' => null),
    array('id' => 3, 'text' => 'Комментарий 3', 'parent_id' => 1),
    array('id' => 4, 'text' => 'Комментарий 4', 'parent_id' => 1),
    array('id' => 5, 'text' => 'Комментарий 5', 'parent_id' => 2),
    array('id' => 6, 'text' => 'Комментарий 6', 'parent_id' => 2),
    array('id' => 7, 'text' => 'Комментарий 7', 'parent_id' => 4),
    array('id' => 8, 'text' => 'Комментарий 8', 'parent_id' => 4),
    array('id' => 9, 'text' => 'Комментарий 9', 'parent_id' => 5),
    array('id' => 10, 'text' => 'Комментарий 10', 'parent_id' => 7),
);

И хочу чтобы например "Комментарий 9" был под Комментарием 2 потому что выше уже нету, а Комментария 10 самый родительский был Комментарий 1.

Вот так сперва делал древовидную структуру, а потом преобразовал в двумерный с одним родителем. Всё почти работает, но не показывает сами родительские комментарии.

function buildCommentTree($comments, $parent_id = 0, $depth = 0) {
    $comment_tree = array();
    foreach ($comments as $comment) {
        if ($comment['parent_id'] == $parent_id) {
            $comment['depth'] = $depth;
            $comment['children'] = buildCommentTree($comments, $comment['id'], $depth + 1);
            $comment_tree[] = $comment;
        }
    }
    return $comment_tree;
}
$comment_tree = buildCommentTree($comments);
$resArray = []; 
function convertToSimpleArray($array){
    global $resArray;
    if(!empty($array['children'])){
        foreach($array['children'] as $below){
            $res = convertToSimpleArray($below);
            $below['children'] = [];
            $resArray[] = $below; 
        }
    }else{
        $resArray[] = $array; 
    }
    return $resArray; 
}
foreach ($comment_tree as $comm_tree) {
    $arrr[] = array_unique(convertToSimpleArray($comm_tree), SORT_REGULAR);
    $resArray = [];
}

Первый родитель

Второй родитель

Ответы

▲ 0Принят

Поскольку ваш код несколько громоздкий, приведу более простой пример. сделайте сначала два подготовительных шага. Первое - проиндексируйте массив по id.

$data = array_column($comments, null, 'id');

Теперь создайте функцию, которая пройдется вверх по массиву и вернет максимальный родительский id для элемента:

$getTopParent = function($id) use ($data) {
    while($parentId = $data[$id]['parent_id']) $id = $parentId;
    return $id;
};

С ее помощью теперь обработайте исходный массив, заменив родительские id где надо, а где не надо, добавим replies для ответов:

foreach ($data as $id => &$comment) {
    if (!$comment['parent_id']) {
        $comment['replies'] = [];
    } else {
        $comment['parent_id'] = $getTopParent($id);
    }
}

Вторым циклом перенесите ответы в ветки:

foreach ($data as $id => $item) {
    if ($pid = $item['parent_id']) {
        $data[$pid]['replies'][$id] = $item;
        unset($data[$id]);
    }
}

в целом, можно объединить в рамках одного цикла:

foreach ($data as $id => &$comment) {
    if ($comment['parent_id']) {
        $comment['parent_id'] = $pid = $getTopParent($id);
        $data[$pid]['replies'][$id] = $comment;
        unset($data[$id]);
    }
}