PHP - a simple array of nested unordered lists (UL)

I saw several variations of this nested UL array question in stackoverflow, but I find mine easier than others. I am looking for a simple cycle loop that allows you to resolve an infinite number of topics (parents) with an infinite number of elements (children), for example:

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

I tried to do this with the following code:

 <?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']; } ?> 

The above code displays the following:

 * 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 

I would like the code to display the following:

 * 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 

Any ideas would be greatly appreciated!

QUESTION RESOLVED BY BRAND; can this related issue be resolved?

Hi Mark: Yes, it did the trick! Very helpful, thanks. I was wondering if you can help me translate this to another level of difficulty. If you think you should not ask a question in this question, let me know and I will ask separately, but your code is strong, so I thought that I would follow it.

Using the same code above, I hope to provide the user with the ability to view data on a choice of 1 column, 2 columns, 3 columns, 4 columns, 5 columns, etc. (to 10). The data lines will be divided into separate DIV tags, and the number of lines will include both topics and news items. I will control the DIV tags using my CSS, but I would like to group the row count evenly into DIV tags for the specified number of columns. I would like children’s news articles not to be separated from their parents and groups in order to be as large as possible. If there is a breakpoint at which 1 column can be longer than the other, and it is equal / arbitrary, the priority will go to the leftmost column, for example: this mini-illustration:

 XXX XX X 

I do not know how clear this is, so here is an example. If the user selects 1 column, they will see the following 30 "rows" of data:

 <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> 

If the user selects 2 columns, they will see the next 30 “rows” of data, divided into 2 groups with DIV tags wrapped around each. This happens to space outside by coincidence:

 <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> 

If the user selects 3 columns, they will see the next 30 “rows” of data, divided into 3 groups with DIV tags wrapped around each. The interval starts to get complicated, and I'm open to suggestions.

 <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> 

If the user selects 4 columns, they will see the next 30 “rows” of data, divided into 4 groups with DIV tags wrapped around each. Again, I don’t even know how to manually place this for illustration, but it is important that the children remain under the parent.

 <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> 
+4
source share
1 answer

This should do the trick:

 $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>'; 

I think your real problem is that you open two lists each time, but only close one (even moving the last block inside the list).


For the second part of your (new) question:

I cautioned that for larger lists (say, over 300 items), the compromise I make regarding storing the list in memory and repeating it twice, rather than just counting requests, should swing in a different way. That is, the solution below puts everything in memory, and then repeats a second time to print it; an alternative would be to run two queries, one to find the number of unique topic names and one to find the number of common items in the list.

In addition, for display, you really want to solve some optimization for the layout, I will do it naively and just do (approximately) an equal number of topics for each column, and when the unit does not work, it will have a left weight. You will see where you can tune or replace some code to get other (and better?) Results.

 $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>'; } 
+1
source

Source: https://habr.com/ru/post/1341731/


All Articles