PHP – простой массив вложенных неупорядоченных списков (UL)

Я видел несколько вариантов этого вложенного вопроса массива UL в stackoverflow, но я считаю, что мой проще других. Я ищу простой цикл цикла, который позволяет допускать бесконечное количество тем (родителей) с бесконечным количеством элементов (детей), например:

<ul> <li>Topic</li> <ul> <li>Item</li> <li>Item</li> <li>Item</li> <li>Item</li> </ul> </ul> 

Я попытался сделать это с помощью следующего кода:

 <?php $result = mysql_query("SELECT * FROM News"); $topicname = false; while($row = mysql_fetch_array($result)) { if (!$row['TopicID']) { $row['TopicName'] = 'Sort Me'; } if ($topicname != $row['TopicName']) { echo '<ul><li>' . $row['TopicName'] . '</li><ul>'; $topicname = $row['TopicName']; } echo ''; echo '<li>' . $row['NewsID'] . '"</li>'; echo ''; } if ($topicname != $row['TopicName']) { echo '</ul>'; $topicname = $row['TopicName']; } ?> 

Вышеприведенный код отображает следующее:

 * Topic A o News 1 o News ... o News 51000 + Topic B # News 1 # News ... # News 51000 * Topic C o News 1 o News ... o News 51000 + Topic D # News 1 # News ... # News 51000 

Хотелось бы, чтобы код отображал следующее:

 * Topic A o News 1 o News ... o News 51000 * Topic B o News 1 o News ... o News 51000 * Topic C o News 1 o News ... o News 51000 * Topic D o News 1 o News ... o News 51000 

Благодарим за любую идею!

ВОПРОС, РЕШЕННЫЙ МАРКОМ; можно решить этот смежный вопрос?

Привет Марк: Да, это сделал трюк! Очень полезно, спасибо. Мне было интересно, можете ли вы помочь мне перевести это на другой уровень сложности. Если вы считаете, что в этом вопросе не стоит задавать вопросы, дайте мне знать, и я спрошу отдельно, но ваш код прочен, поэтому я подумал, что буду следить за ним.

Используя тот же код выше, я надеюсь предоставить пользователю возможность просматривать данные с помощью выбора 1 колонки, 2 столбца, 3 столбца, 4 столбца, 5 столбцов и т. Д. (До 10). Строки данных будут разделены на отдельные теги DIV, а количество строк будет включать как темы, так и новостные элементы. Я буду контролировать теги DIV с помощью моего CSS, но я хотел бы группировать счетчик строк равномерно в теги DIV для указанного количества столбцов. Я хотел бы, чтобы новостные статьи детей не были отделены от их родителей и групп, чтобы быть как можно более. Если есть точка прерывания, где 1 столбец может быть длиннее другого, и он четный / произвольный, приоритет будет идти в самый левый столбец, например: эта мини-иллюстрация:

 XXX XX X 

Я не знаю, насколько это понятно, так вот пример. Если пользователь выбирает 1 столбец, они будут видеть следующие 30 «строк» ​​данных:

 <div id="Columns1Group1of1"> * Topic A o News 1 o News 2 o News 3 * Topic B o News 1 o News 2 o News 3 o News 4 * Topic C o News 1 o News 2 o News 3 o News 4 o News 5 * Topic D o News 1 o News 2 o News 3 * Topic E o News 1 o News 2 o News 3 o News 4 * Topic F o News 1 o News 2 o News 3 o News 4 o News 5 </div> 

Если пользователь выбирает 2 столбца, они будут видеть следующие 30 «строк» ​​данных, разделенных на 2 группы с тегами DIV, обернутыми вокруг каждого. Это случается, когда пространство просто красиво по совпадению:

 <div id="Columns2Group1of2"> <div id="Columns2Group2of2"> * Topic A * Topic D o News 1 o News 1 o News 2 o News 2 o News 3 o News 3 * Topic B * Topic E o News 1 o News 1 o News 2 o News 2 o News 3 o News 3 o News 4 o News 4 * Topic C * Topic F o News 1 o News 1 o News 2 o News 2 o News 3 o News 3 o News 4 o News 4 o News 5 o News 5 </div> </div> 

Если пользователь выбирает 3 столбца, они будут видеть следующие 30 «строк» ​​данных, разделенных на 3 группы с тегами DIV, обернутыми вокруг каждого. Интервал начинает становиться сложным, и я открыт для предложений.

 <div id="Columns3Group1of3"> <div id="Columns3Group2of3"> <div id="Columns3Group3of3"> * Topic A * Topic C * Topic E o News 1 o News 1 o News 1 o News 2 o News 2 o News 2 o News 3 o News 3 o News 3 * Topic B o News 4 o News 4 o News 1 o News 5 * Topic F o News 2 * Topic D o News 1 o News 3 o News 1 o News 2 o News 4 o News 2 o News 3 </div> o News 3 o News 4 </div> o News 5 </div> 

Если пользователь выбирает 4 столбца, они будут видеть следующие 30 «строк» ​​данных, разделенных на 4 группы с тегами DIV, обернутыми вокруг каждого. Опять же, я даже не знаю, как вручную разместить это для иллюстрации, но важно, чтобы дети оставались под родителем.

 <div id="Columns4Group1of4"> <div id="Columns4Group2of4"> <div id="Columns4Group3of4"> <div id="Columns4Group4of4"> * Topic A * Topic C * Topic D * Topic F o News 1 o News 1 o News 1 o News 1 o News 2 o News 2 o News 2 o News 2 o News 3 o News 3 o News 3 o News 3 * Topic B o News 4 * Topic E o News 4 o News 1 o News 5 o News 1 o News 5 o News 2 </div> o News 2 </div> o News 3 o News 3 o News 4 o News 4 </div> </div> 

Это должно сделать трюк:

 $result = mysql_query("SELECT * FROM News"); $topicname = ''; // open list of topics echo '<ul>'; // loop through topics while($row = mysql_fetch_array($result)) { if (!$row['TopicID']) { // fake topic name for unsorted stuff $row['TopicName'] = 'Sort Me'; } if ($topicname != $row['TopicName']) { if($topicname != ''){ // had a topic name, means we opened a list // that hasn't been closed, close it. echo '</ul>'; } // print this topic and open the list of articles echo '<li>' . $row['TopicName'] . '</li><ul>'; // update the current topic to be this TopicName $topicname = $row['TopicName']; } // the news item echo '<li>' . $row['NewsID'] . '"</li>'; } if($topicname != ''){ // we saw at least one TopicName, we need to close // the last open list. echo '</ul>'; } // end topic list echo '</ul>'; 

Я думаю, что ваша настоящая проблема заключается в том, что вы каждый раз открывали два списка, но только закрывали один (даже перемещая последний блок внутри списка).


Для второй части вашего (нового) вопроса:

Я буду предупреждать, что для более крупных списков (скажем, более 300 элементов) компромисс, который я делаю в отношении хранения списка в памяти и повторного повторения дважды, а не просто для запроса необходимых счетчиков, будет качаться другим способом. То есть, решение ниже помещает все в память, а затем повторяет второй раз, чтобы распечатать его; альтернативой было бы запустить два запроса, один, чтобы найти количество уникальных имен темы и один, чтобы найти количество общих элементов в списке.

Кроме того, для отображения вы действительно хотите решить некоторую оптимизацию для макета, я сделаю это наивно и просто сделаю (примерно) равное количество тем в столбце, а когда деление не сработает, это будет весом влево. Вы увидите, где вы можете изменить или заменить какой-либо код, чтобы получить другие (и лучше?) Результаты.

 $columns = // user specified; $result = mysql_query("SELECT * FROM News"); $num_articles = 0; // $dataset will contain array( 'Topic1' => array('News 1', 'News2'), ... ) $dataset = array(); while($row = mysql_fetch_array($result)) { if (!$row['TopicID']) { $row['TopicName'] = 'Sort Me'; } $dataset[$row['TopicName']][] = $row['NewsID']; $num_articles++; } $num_topics = count($dataset); // naive topics to column allocation $topics_per_column = ceil($num_topics / $columns); $i = 0; // keeps track of number of topics printed $c = 1; // keeps track of columns printed foreach($dataset as $topic => $items){ if($i % $topics_per_columnn == 0){ if($i > 0){ echo '</ul></div>'; } echo '<div class="Columns' . $columns . 'Group' . $c . '"><ul>'; $c++; } echo '<li>' . $topic . '</li>'; // this lists the articles under this topic echo '<ul>'; foreach($items as $article){ echo '<li>' . $article . '</li>'; } echo '</ul>'; $i++; } if($i > 0){ // saw at least one topic, need to close the list. echo '</ul></div>'; }