带有分组项的PHP Foreach循环

时间:2014-01-22 02:03:52

标签: php arrays sorting foreach

我有一系列状态,我想要做的是按首字母对它们进行分类,然后显示这些组。我几乎正常工作,最后一个问题是:

what I have so far

我希望所有状态都在逗号分隔的单个框中,而不是每个状态都在它自己的灰色框中。这是我的代码:

<?
    $lastChar = '';
    sort($state_list, SORT_STRING | SORT_FLAG_CASE);

    foreach ($state_list as $state) {
        $char = $state[0];
        echo "<div class=\"stateTable\">";
        if ($char !== $lastChar) {
            echo "<div class=\"stateTopRow\">" . strtoupper($char) . "</div>";
                echo "<div class=\"clear\"></div>";
        $lastChar = $char;
        }
            echo "<div class=\"stateBody\">" . $state . "</div>";
                echo "<div class=\"clear\"></div>";
        echo "</div>";
    }
?>

问题在于它为每个单独的状态循环整个stateBody div。我试过在if语句中以某种方式包括stateBody,但这完全打破了样式(并且理所当然)。

有没有办法在if语句中包含stateBody,然后添加另一个foreach来循环通过相应的状态?谢谢!

5 个答案:

答案 0 :(得分:5)

我会建议采用略有不同的方法。由于您最终希望将它们全部分组,因此最好通过相应地组织阵列来开始。循环遍历它,并创建一个新数组,其子数组由第一个字母索引。在迭代原始数组时,在适当字符的索引处追加到新数组。然后,为您的输出循环更容易。

通常最好将数据格式化为最终需要的结构,以便稍后简化输出逻辑。

// Start by sorting as you already did
sort($state_list, SORT_STRING | SORT_FLAG_CASE);

// Create a new array
$output_array = array();

// Loop over the one you have...
foreach ($state_list as $state) {
  $first = strtoupper($state[0]);
  // Create the sub-array if it doesn't exist
  if (!isset($output_array[$first])) {
    $ouput_array[$first] = array();
  }

  // Then append the state onto it
  $output_array[$first][] = $state;
}

结果数组如下所示:

Array
(
    [A] => Array
        (
            [0] => Alabama
            [1] => Arkansas
            [2] => Alaska
        )

    [C] => Array
        (
            [0] => Connecticut
        )

)

现在你需要一个简单的循环和一个implode()来产生你的输出:

// For clarity, I omitted your surrounding <div> markup
// this is just the first letter and the state lists...
foreach($output_array as $state_index => $states) {
  // The index is the first letter...
  echo "<div class='stateTopRow'>$state_index</div>";

  // And the sub-array can be joined with implode()
  echo "<div class='stateBody'>" . implode(', ', $states) . "</div>";
}

答案 1 :(得分:0)

<?
    $lastChar = '';
    sort($state_list, SORT_STRING | SORT_FLAG_CASE);
    $cnt = 0;

    echo "<div class=\"stateTable\">";
    foreach ($state_list as $state) {
        $char = $state[0];

        if ($char !== $lastChar) {
            if (($char !== 'a') && ($char !== 'A')) {
                echo "</div><div class=\"clear\"></div>";   // close off last state list 
            }
            echo "<div class=\"stateTopRow\">" . strtoupper($char) . "</div>";
                echo "<div class=\"clear\"></div>";
            $lastChar = $char;
            $cnt = 0;
        }
        if ($cnt == 0) {
            echo "<div class=\"stateBody\">" . $state;
        } else {
            echo ", " . $state;
        }
            $cnt++;
    }
    echo "</div>";
?>

答案 2 :(得分:0)

$lastChar = '';
sort($state_list, SORT_STRING | SORT_FLAG_CASE);

echo "<div class='stateTable'>";
foreach ($state_list as $state)
{
    $char = $state[0];
    if ($char != $lastChar)
    {
        if ($lastChar != '')
            echo "</div><div class='clear' />"; // close previous state list
        $lastChar = $char;
        echo "<div class='stateTopRow'>" . strtoupper($char) . "</div>";
        echo "<div class='stateBody'>$state"; // open new state list
    }
    else // next state name
    {
        echo ", $state";
    }
}
echo "</div><div class='clear' />"; // close last list
echo "</div>";                      // close whole table

正如另一位评论者所说,混合输出和数据组织很少是一个好的理念 看看你把问题分开后会变得多么简单:

// sort all states alphabetically
sort($state_list, SORT_STRING | SORT_FLAG_CASE);

// split names according to their initial
foreach ($state_list as $state)
    $alpha_table[$state[0]][] = $state;

// output each letter group
foreach ($alpha_table as $letter => $list)
{
    echo "<div class='stateTopRow'>".strtoupper($letter) ."</div>". // header
         "<div class='stateBody'>"  .implode (",", $list)."</div>". // list
         "<div class='clear' />";                                   // separator
}

答案 3 :(得分:0)

如果要将所有内容保存在一次扫描中(性能方面),我建议如下:

<?
        $lastChar = '';
        sort($state_list, SORT_STRING | SORT_FLAG_CASE);

        foreach ($state_list as $state) {
            $char = $state[0];
             $states_arr = array();
            echo "<div class=\"stateTable\">";

                 if ($char !== $lastChar) {
                   echo "<div class=\"stateTopRow\">" . strtoupper($char) . "</div>";
                   echo "<div class=\"clear\"></div>";

                   //if not the first letter
                   if ($lastChar) {
                     echo "</div>";//end the stateDiv div
                     echo implode($states_arr,', ');//print the states with commas
                   }

                   //open the stateBody div
                   echo "<div class=\"stateBody\">";

                    $lastChar = $char;
                }

                //add state to the array but don't print yet
                $states_arr[] = $state;

                echo "<div class=\"clear\"></div>";
            echo "</div>";
        }
    ?>

如果性能不是一个因素,您可能希望实际运行2​​次扫描 - 第一次扫描组织数据,第二次扫描显示数据。

但是,上述方法应该按照您的要求运作。

希望这有帮助!

答案 4 :(得分:0)

<?php
$state_list= array("alabama", "alaska", "arkansas");
$lastChar = '';
sort($state_list, SORT_STRING | SORT_FLAG_CASE);

foreach ($state_list as $state) {
    $char = $state[0];
    echo "<div>";
    echo "<div class=\"stateTable\">";
    if ($char !== $lastChar) {
        echo "<div class=\"stateTopRow\">" . strtoupper($char) ."</div>";
            echo "<div class=\"clear\"></div>";
    $lastChar = $char;
    }
}
$states= implode(",", $state_list);
echo $states;
?>