Задать вопрос

Как сформировать список по вложенному массиву рекурсивной функцией?

Требуется реализовать рекурсивную функцию, которая на основе массива (который может иметь неограниченную вложенность) формирует список с помощью тегов ul и li. При этом можно использовать только один аргумент! и тег ul должен выводиться только один раз! (открывающий и закрывающий).
Код работает, но нужно сделать по другому, без str_replace и прочего такого.

Вот пример массива:
$arr = [
    'id' => 1,
    'name' => 'item1',
    'items' => [
        ['id' => 2,
        'name' => 'item2',
        'items' => [],
        ],
        ['id' => 3,
        'name' => 'item3',
        'items' => [],
        ],
        [
        'id' => 4,
        'name' => 'item4',
        'items' => [
            ['id' => 5,
            'name' => 'item5',
            'items' => [],
            ],
            ['id' => 6,
            'name' => 'item6',
            'items' => [],
            ]
        ]
        ]
    ]
];

Какой код у меня сейчас
function list_form(array $array) {
    $str = '';
    foreach ($array as $key => $val) {
        if (is_array($val)) {
            $str .= "<li>$key =></li>";
            
            if (!empty($val)) {
                $str .= list_form($val);
            }
        }
        else {
            $str .= "<li>$key => $val</li>";
        }
    }
    return "<ul>" . str_replace(["<ul>", "</ul>"], '', $str) . "</ul>";
}
echo list_form($arr);
  • Вопрос задан
  • 128 просмотров
Подписаться 1 Средний 11 комментариев
Пригласить эксперта
Ответы на вопрос 3
Rsa97
@Rsa97
Для правильного вопроса надо знать половину ответа
Ну, будем извращаться.
<?php
function formatList(array $list): string
{
    $result = '';
    foreach ($list as $key => $value) {
        if (!is_array($value)) {
            $result .= "<li>{$key} => {$value}</li>";
            continue;
        }
        $result .= "<li>{$key} =></li>";
        foreach ($value as $item) {
            $result .= formatList($item);
        }
    }
    if ((debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]['function'] ?? '') !== 'formatList') {
        $result = "<ul>{$result}</ul>";
    }
    return $result;
}
print formatList($arr);

<ul><li>id => 1</li><li>name => item1</li><li>items =></li><li>id => 2</li><li>name => item2</li><li>items =></li><li>id => 3</li><li>name => item3</li><li>items =></li><li>id => 4</li><li>name => item4</li><li>items =></li><li>id => 5</li><li>name => item5</li><li>items =></li><li>id => 6</li><li>name => item6</li><li>items =></li></ul>
Ответ написан
IvanU7n
@IvanU7n
nothing interesting here
непонятно должна ли быть функция рекурсивная
сделал итеративную версию с состоянием
<?php
$arr = [ 'id' => 1, 'name' => 'item1', 'items' => [
	[ 'id' => 2, 'name' => 'item2', 'items' => [], ],
	[ 'id' => 3, 'name' => 'item3', 'items' => [], ],
	[ 'id' => 4, 'name' => 'item4', 'items' => [
		[ 'id' => 5, 'name' => 'item5', 'items' => [], ],
		[ 'id' => 6, 'name' => 'item6', 'items' => [], ],
	], ],
], ];

function list_form_iterative(array $input) {
	$result = [ '<ul>', ];
	$state = [ [ 'array' => $input, 'keys' => array_keys($input), 'idx' => 0, ] ];
	for (; count($state) > 1 || $state[0]['idx'] < count($state[0]['keys']); $state[0]['idx'] += 1) {
		if (count($state) > 1 && $state[0]['idx'] === count($state[0]['keys'])) {
			array_shift($state);
			continue;
		}
		$key = $state[0]['keys'][$state[0]['idx']];
		$value = $state[0]['array'][$key];
		if (!is_array($value)) {
			$result[] = "<li>$key => $value</li>";
		}
		else {
			$result[] = "<li>$key => []</li>";
			if (!count($value)) continue;
			array_unshift($state, [ 'array' => $value, 'keys' => array_keys($value), 'idx' => -1, ]);
		}
	}
	$result[] = '</ul>';
	return implode("\n", $result);
}

echo list_form_iterative($arr);


оказалось, что рекурсивность обязательна
<?php
$arr = [ 'id' => 1, 'name' => 'item1', 'items' => [
	[ 'id' => 2, 'name' => 'item2', 'items' => [], ],
	[ 'id' => 3, 'name' => 'item3', 'items' => [], ],
	[ 'id' => 4, 'name' => 'item4', 'items' => [
		[ 'id' => 5, 'name' => 'item5', 'items' => [], ],
		[ 'id' => 6, 'name' => 'item6', 'items' => [], ],
	], ],
], ];

function list_form_recursive(array $input) {
	static $level = 0;
	$self = __FUNCTION__;
	$result = [];
	if (!$level) {
		$result[] = '<ul>';
	}
	foreach ($input as $key => $value) {
		if (!is_array($value)) {
			$result[] = "<li>$key => $value</li>";
		}
		else {
			$result[] = "<li>$key => []</li>";
			if (!count($value)) continue;
			$level += 1;
			array_push($result, ...$self($value));
			$level -= 1;
		}
	}
	if (!$level) {
		$result[] = '</ul>';
		return implode("\n", $result);
	}
	else {
		return $result;
	}
}

echo list_form_recursive($arr);

вывод обоих функций
<ul>
<li>id => 1</li>
<li>name => item1</li>
<li>items => []</li>
<li>0 => []</li>
<li>id => 2</li>
<li>name => item2</li>
<li>items => []</li>
<li>1 => []</li>
<li>id => 3</li>
<li>name => item3</li>
<li>items => []</li>
<li>2 => []</li>
<li>id => 4</li>
<li>name => item4</li>
<li>items => []</li>
<li>0 => []</li>
<li>id => 5</li>
<li>name => item5</li>
<li>items => []</li>
<li>1 => []</li>
<li>id => 6</li>
<li>name => item6</li>
<li>items => []</li>
</ul>
Ответ написан
извращение с мухлежом:
<?php
function list_form(array $items):string
{
     function inner(array $items):string {
        $result = '';
        foreach ($items as $key => $val) {
            if (is_array($val) ) {
                $result .= "<li>$key =></li>";

                if (!empty($val)) {
                    $result .= inner($val);
                }
            } else {
                $result .= "<li>$key => $val</li>";
            }
        }
        return $result;
    }

    return '<ul>'.inner($items).'</ul>';
}
echo list_form($arr);
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы