PHP - 简单嵌套无序列表(UL)数组

时间:2021-04-10 21:17:07

I have seen a few variants of this nested UL array question on *, but I think mine is simpler than the others. I am looking for a simple array loop that allows allows for an infinite amount of topics (parents) with an infinite amount of items (children), like:

我已经在*上看到了这个嵌套的UL数组问题的一些变体,但我认为我的比其他更简单。我正在寻找一个简单的数组循环,允许无限量的主题(父母)与无限量的项目(儿童),如:

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

I have attempted 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 renders 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

The would like the code to render 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 SOLVED BY MARK; possible to solve this related question?

马克解决的问题;有可能解决这个相关的问题吗?

Hi Mark: Yes, this did the trick! Very helpful, thank you. I was wondering if you might be able to help me take this to another level of sophistication. If you think it is not appopriate to ask within this question, let me know and I will ask separately, but your code is solid, so I thought I would follow up with it.

嗨Mark:是的,这就行了!非常有帮助,谢谢。我想知道你是否能够帮我把它带到另一个复杂程度。如果你认为在这个问题中提出问题是不合适的,请告诉我,我会另外提出,但你的代码是可靠的,所以我想我会跟进它。

Using the same code above, I am hoping to give the user the option to view the data via the choice of 1 column, 2 columns, 3 columns, 4 columns, 5 columns, etc. (up to 10). The rows of data would be divided into separate DIV tags and the row count would include both the topics and the news items. I will control the DIV tags with my CSS, but I would like to group the row count evenly into DIV tags for the specified amount of columns. I would like the children news items to not be separated from their parent and the groups to be as even as possible. If there is a breaking point where 1 column can be longer than the other and it's even/arbitrary, precedence would go to the left-most column, like: this mini-illustration:

使用上面相同的代码,我希望通过选择1列,2列,3列,4列,5列等(最多10个)为用户提供查看数据的选项。数据行将被分成单独的DIV标记,行计数将包括主题和新闻项。我将使用我的CSS控制DIV标签,但我想将行计数均匀地分组到指定数量的列的DIV标签中。我希望儿童新闻项目不要与父母和群体分开,以尽可能地分开。如果有一个断点,其中1列可以比另一列长,并且它是偶数/任意的,优先级将转到最左边的列,如:这个迷你插图:

XXX
XX
X

I don't know how clear this is, so here is an example. If the user chooses 1 column, they would see the following 30 "rows" of data:

我不知道这有多清楚,所以这里有一个例子。如果用户选择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>

If the user chooses 2 columns, they would see the following 30 "rows" of data divided into 2 groups with DIV tags wrapped around each. This happens to space out nicely by coincidence:

如果用户选择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>

If the user chooses 3 columns, they would see the following 30 "rows" of data divided into 3 groups with DIV tags wrapped around each. The spacing is starting to get tricky and I am open to suggestions.

如果用户选择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>

If the user chooses 4 columns, they would see the following 30 "rows" of data divided into 4 groups with DIV tags wrapped around each. Again, I don't even know how to manually space it for my illustration, but it is important for the children to stay under the parent.

如果用户选择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>

1 个解决方案

#1


1  

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 were opening two lists each time, but only closing one (even moving the last block inside the list).

我认为你真正的问题是你每次打开两个列表,但只关闭一个(甚至移动列表中的最后一个块)。


For the second part of your (new) question:

对于(新)问题的第二部分:

I'll caveat that for larger lists (say, more than 300 items) the tradeoff I'm making with respect to storing the list in memory and iterating twice rather than just querying for counts needed would swing the other way. That is, the solution below puts everything into memory, then iterates a second time to print it out; an alternative would be to run two queries, one to find the number of unique TopicNames and one to find the number of total items in the list.

我要指出的是,对于较大的列表(比如超过300个项目),我在制作关于将列表存储在内存中并进行两次迭代而不仅仅是查询所需的计数的权衡将以另一种方式摆动。也就是说,下面的解决方案将所有内容放入内存,然后再次迭代打印出来;另一种方法是运行两个查询,一个用于查找唯一的TopicNames的数量,另一个用于查找列表中的总项数。

Also, for display, you really want to solve some optimization for layout, I'll do this naively and just make a (roughly) equal number of topics per column and when the division doesn't work out this will weight towards the left. You'll see where you can tweak or replace some code to get different (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


1  

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 were opening two lists each time, but only closing one (even moving the last block inside the list).

我认为你真正的问题是你每次打开两个列表,但只关闭一个(甚至移动列表中的最后一个块)。


For the second part of your (new) question:

对于(新)问题的第二部分:

I'll caveat that for larger lists (say, more than 300 items) the tradeoff I'm making with respect to storing the list in memory and iterating twice rather than just querying for counts needed would swing the other way. That is, the solution below puts everything into memory, then iterates a second time to print it out; an alternative would be to run two queries, one to find the number of unique TopicNames and one to find the number of total items in the list.

我要指出的是,对于较大的列表(比如超过300个项目),我在制作关于将列表存储在内存中并进行两次迭代而不仅仅是查询所需的计数的权衡将以另一种方式摆动。也就是说,下面的解决方案将所有内容放入内存,然后再次迭代打印出来;另一种方法是运行两个查询,一个用于查找唯一的TopicNames的数量,另一个用于查找列表中的总项数。

Also, for display, you really want to solve some optimization for layout, I'll do this naively and just make a (roughly) equal number of topics per column and when the division doesn't work out this will weight towards the left. You'll see where you can tweak or replace some code to get different (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>';
}