问题很简单。我的代码中有一个foreach
循环。
foreach($array as $element) {
//code
}
在这个循环中,当我们处于第一次或最后一次迭代时,我想做出不同的反应。
如何做到这一点?
如果你喜欢一个不需要在循环外初始化计数器的解决方案,我建议将当前的迭代键与告诉你数组最后/第一个键的函数进行比较。
在即将到来的 PHP 7.3 中,这将变得更加有效(和更易读)。
foreach($array as $key => $element) {
if ($key === array_key_first($array))
echo 'FIRST ELEMENT!';
if ($key === array_key_last($array))
echo 'LAST ELEMENT!';
}
foreach($array as $key => $element) {
reset($array);
if ($key === key($array))
echo 'FIRST ELEMENT!';
end($array);
if ($key === key($array))
echo 'LAST ELEMENT!';
}
一个更简化的版本,假设你没有使用自定义索引......
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
} else if ($index == $len - 1) {
// last
}
}
版本2--因为我已经开始厌恶使用else,除非必要。
$len = count($array);
foreach ($array as $index => $item) {
if ($index == 0) {
// first
// do something
continue;
}
if ($index == $len - 1) {
// last
// do something
continue;
}
}
你可以把数组中的第一个和最后一个元素去掉,然后分别处理它们。
像这样。
<?php
$array = something();
$first = array_shift($array);
$last = array_pop($array);
// do something with $first
foreach ($array as $item) {
// do something with $item
}
// do something with $last
?>
把所有的格式化内容删除到CSS中,而不是内联标签,会改善你的代码,加快加载时间。
你也可以尽可能地避免将HTML与php逻辑混合。
通过这样的分离,你的页面可以变得更有可读性和可维护性。
<?php
function create_menu($params) {
//retirive menu items
//get collection
$collection = get('xxcollection') ;
foreach($collection as $c) show_collection($c);
}
function show_subcat($val) {
?>
<div class="sub_node" style="display:none">
<img src="../images/dtree/join.gif" align="absmiddle" style="padding-left:2px;" />
<a id="'.$val['xsubcatid'].'" href="javascript:void(0)" onclick="getProduct(this , event)" class="sub_node_links" >
<?php echo $val['xsubcatname']; ?>
</a>
</div>
<?php
}
function show_cat($item) {
?>
<div class="node" >
<img src="../images/dtree/plus.gif" align="absmiddle" class="node_item" id="plus" />
<img src="../images/dtree/folder.gif" align="absmiddle" id="folder">
<?php echo $item['xcatname']; ?>
<?php
$subcat = get_where('xxsubcategory' , array('xcatid'=>$item['xcatid'])) ;
foreach($subcat as $val) show_subcat($val);
?>
</div>
<?php
}
function show_collection($c) {
?>
<div class="parent" style="direction:rtl">
<img src="../images/dtree/minus.gif" align="absmiddle" class="parent_item" id="minus" />
<img src="../images/dtree/base.gif" align="absmiddle" id="base">
<?php echo $c['xcollectionname']; ?>
<?php
//get categories
$cat = get_where('xxcategory' , array('xcollectionid'=>$c['xcollectionid']));
foreach($cat as $item) show_cat($item);
?>
</div>
<?php
}
?>
简单的说就是这个效果!
// Set the array pointer to the last key
end($array);
// Store the last key
$lastkey = key($array);
foreach($array as $key => $element) {
....do array stuff
if ($lastkey === key($array))
echo 'THE LAST ELEMENT! '.$array[$lastkey];
}
感谢@billynoah对**终问题的整理。
1: 为什么不使用一个简单的for
语句?假设你使用的是一个真实的数组,而不是一个`迭代器',你可以很容易地检查计数器变量是0还是比整个元素数少一个。在我看来,这是最干净、最容易理解的解决方案...
$array = array( ... );
$count = count( $array );
for ( $i = 0; $i < $count; $i++ )
{
$current = $array[ $i ];
if ( $i == 0 )
{
// process first element
}
if ( $i == $count - 1 )
{
// process last element
}
}
2:你应该考虑使用Nested Sets来存储你的树状结构。另外,你可以通过使用递归函数来改进整个事情。
最佳答案:
$arr = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
foreach ($arr as $a) {
// This is the line that does the checking
if (!each($arr)) echo "End!\n";
echo $a."\n";
}
$arr = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
foreach ($arr as $a) {
// This is the line that does the checking
if (!each($arr)) echo "End!\n";
echo $a."\n";
}
来自@morg的最高效的答案,与foreach
不同,它只适用于适当的数组,而不是哈希映射对象。
这个答案避免了像大多数答案(包括被接受的答案)那样,在循环的每一次迭代中使用条件语句的开销,因为它*具体地处理了第一个和最后一个元素,并对中间的元素进行循环。
可以使用array_keys
函数来使高效答案像foreach
一样工作。
$keys = array_keys($arr);
$numItems = count($keys);
$i=0;
$firstItem=$arr[$keys[0]];
# Special handling of the first item goes here
$i++;
while($i<$numItems-1){
$item=$arr[$keys[$i]];
# Handling of regular items
$i++;
}
$lastItem=$arr[$keys[$i]];
# Special handling of the last item goes here
$i++;
我还没有对此做基准测试,但没有在循环中添加任何逻辑,这是对性能影响最大的地方,所以我怀疑提供的高效答案的基准非常接近。
如果你想把这种东西**功能化,我'已经尝试过这样一个[这里的iterateList函数](https://gist.github.com/TheMadDeveloper/71b300211686cc9da1a90a05e4e0a86a)。 虽然,如果你超级关心效率的话,你可能会想要对gist代码进行基准测试。 我不知道所有的函数调用会引入多少开销。
对于SQL查询生成的脚本,或者任何对第一个或最后一个元素做不同操作的脚本,避免使用不必要的变量检查要快得多(几乎是快的两倍)。
目前公认的解决方案是使用一个循环和在循环中进行每一次_single_iteration的检查,正确(快速)的方法是如下。
$numItems = count($arr);
$i=0;
$firstitem=$arr[0];
$i++;
while($i<$numItems-1){
$some_item=$arr[$i];
$i++;
}
$last_item=$arr[$i];
$i++;
自制的一个小基准显示如下。
test1: 100000次运行morg模型
时间: 1869: 1869. 3430423737毫秒
test2: 100000次的模型运行,如果最后
时间:3235.6359958649毫秒 3235. 6359958649毫秒
因此,它'很明显,检查的成本很高,当然,它变得更加糟糕,你添加更多的可变检查;)
使用布尔变量仍然是最可靠的,即使你想检查$value
的第一次出现(我发现在我的情况下和很多情况下它更有用),比如这样。
$is_first = true;
foreach( $array as $value ) {
switch ( $value ) {
case 'match':
echo 'appeared';
if ( $is_first ) {
echo 'first appearance';
$is_first = false;
}
break;
}
}
if( !next( $array ) ) {
echo 'last value';
}
}
那么不如用!next( $array )
来查找最后一个$value
,如果没有next()
值可以迭代,就返回true
。
如果要使用计数器,我更喜欢使用 "for "循环,而不是 "foreach",像这样。
$len = count( $array );
for ( $i = 0; $i < $len; $i++ ) {
$value = $array[$i];
if ($i === 0) {
// first
} elseif ( $i === $len - 1 ) {
// last
}
// …
$i++;
}
当我遇到同样的问题时,我看到了这个帖子。 我只需要得到第一个元素,然后我重新分析我的代码,直到我想到了这个。
$firstElement = true;
foreach ($reportData->result() as $row)
{
if($firstElement) { echo "first element"; $firstElement=false; }
// Other lines of codes here
}
上面的代码很好很完整,但如果你只需要第一个元素,那么你可以试试这个代码。
不知道是否还有必要。
但是下面的解决方案应该可以和迭代器一起使用,而且不需要count
。
<?php
foreach_first_last(array(), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
foreach_first_last(array('aa'), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
echo PHP_EOL;
foreach_first_last(array('aa', 'bb', 'cc'), function ($key, $value, $step, $first, $last) {
echo intval($first), ' ', intval($last), ' ', $step, ' ', $value, PHP_EOL;
});
echo PHP_EOL;
function foreach_first_last($array, $cb)
{
$next = false;
$current = false;
reset($array);
for ($step = 0; true; ++$step) {
$current = $next;
$next = each($array);
$last = ($next === false || $next === null);
if ($step > 0) {
$first = $step == 1;
list ($key, $value) = $current;
if (call_user_func($cb, $key, $value, $step, $first, $last) === false) {
break;
}
}
if ($last) {
break;
}
}
}
你也可以使用匿名函数。
$indexOfLastElement = count($array) - 1;
array_walk($array, function($element, $index) use ($indexOfLastElement) {
// do something
if (0 === $index) {
// first element‘s treatment
}
if ($indexOfLastElement === $index) {
// last not least
}
});
还有三件事情需要提及。
array_values
来管理你的数组。$element
,你必须通过引用传递它(&$element
)。use
结构中的$indexOfLastElement
旁边列出它们,如果需要的话,同样通过引用。foreach ($arquivos as $key => $item) {
reset($arquivos);
// FIRST AHEAD
if ($key === key($arquivos) || $key !== end(array_keys($arquivos)))
$pdf->cat(null, null, $key);
// LAST
if ($key === end(array_keys($arquivos))) {
$pdf->cat(null, null, $key)
->execute();
}
}
试试这个。
function children( &$parents, $parent, $selected ){
if ($parents[$parent]){
$list = '<ul>';
$counter = count($parents[$parent]);
$class = array('first');
foreach ($parents[$parent] as $child){
if ($child['id'] == $selected) $class[] = 'active';
if (!--$counter) $class[] = 'last';
$list .= '<li class="' . implode(' ', $class) . '"><div><a href="]?id=' . $child['id'] . '" alt="' . $child['name'] . '">' . $child['name'] . '</a></div></li>';
$class = array();
$list .= children($parents, $child['id'], $selected);
}
$list .= '</ul>';
return $list;
}
}
$output .= children( $parents, 0, $p_industry_id);