Найдите последний элемент массива при использовании цикла foreach в PHP
Я пишу создателя SQL-запросов, используя некоторые параметры. В Java очень легко обнаружить последний элемент массива изнутри цикла for, просто проверив текущее положение массива с длиной массива.
for(int i=0; i< arr.length;i++){
boolean isLastElem = i== (arr.length -1) ? true : false;
}
В PHP у них есть нецелочисленные индексы для доступа к массивам. Таким образом, вы должны выполнить итерацию по массиву, используя цикл foreach. Это становится проблематичным, когда вам нужно принять какое-то решение (в моем случае добавить параметр или/и при построении запроса).
Я уверен должен быть какой-то стандартный способ сделать это.
Как вы решаете эту проблему в PHP?
29 answers
Похоже, вы хотите что-то вроде этого:
$numItems = count($arr);
$i = 0;
foreach($arr as $key=>$value) {
if(++$i === $numItems) {
echo "last index!";
}
}
Как говорится, вам не нужно перебирать "массив", используя foreach
в php.
Вы можете получить значение последнего ключа массива с помощью end(array_keys($array))
и сравнить его с текущим ключом:
$last_key = end(array_keys($array));
foreach ($array as $key => $value) {
if ($key == $last_key) {
// last element
} else {
// not last element
}
}
Почему все так сложно?
foreach($input as $key => $value) {
$ret .= "$value";
if (next($input)==true) $ret .= ",";
}
Это добавит a за каждым значением, кроме последнего!
Когда toEnd достигает 0, это означает, что он находится на последней итерации цикла.
$toEnd = count($arr);
foreach($arr as $key=>$value) {
if (0 === --$toEnd) {
echo "last index! $value";
}
}
Последнее значение все еще доступно после цикла, поэтому, если вы просто хотите использовать его для большего количества вещей после цикла, это лучше:
foreach($arr as $key=>$value) {
//something
}
echo "last index! $key => $value";
Если вы не хотите рассматривать последнее значение как специальные внутренние циклы. Это должно быть быстрее, если у вас большие массивы. (Если вы повторно используете массив после цикла в той же области, вам сначала нужно "скопировать" массив).
//If you use this in a large global code without namespaces or functions then you can copy the array like this:
//$array = $originalArrayName; //uncomment to copy an array you may use after this loop
//end($array); $lastKey = key($array); //uncomment if you use the keys
$lastValue = array_pop($array);
//do something special with the last value here before you process all the others?
echo "Last is $lastValue", "\n";
foreach ($array as $key => $value) {
//do something with all values before the last value
echo "All except last value: $value", "\n";
}
//do something special with the last value here after you process all the others?
echo "Last is $lastValue", "\n";
И ответить на ваш исходный вопрос "в моем случае добавить параметр или/и при построении запроса"; это приведет к циклу по всем значениям, а затем объединит их в строку с "и" между ними, но не до первого значения или после последнего значения:
$params = [];
foreach ($array as $value) {
$params[] = doSomething($value);
}
$parameters = implode(" and ", $params);
Уже есть много ответов, но стоит также изучить итераторы, тем более что об этом просили стандартным способом:
$arr = range(1, 3);
$it = new CachingIterator(new ArrayIterator($arr));
foreach($it as $key => $value)
{
if (!$it->hasNext()) echo 'Last:';
echo $value, "\n";
}
Возможно, вы найдете что-то более гибкое и для других случаев.
Итак, если ваш массив имеет уникальные значения массива, то определение последней итерации тривиально:
foreach($array as $element) {
if ($element === end($array))
echo 'LAST ELEMENT!';
}
Как вы видите, это работает, если последний элемент появляется только один раз в массиве, в противном случае вы получите ложную тревогу. В нем нет, вы должны сравнить ключи (которые наверняка уникальны).
foreach($array as $key => $element) {
end($array);
if ($key === key($array))
echo 'LAST ELEMENT!';
}
Также обратите внимание на строгий оператор сопоставления, что в данном случае весьма важно.
Предполагая, что массив хранится в переменной...
foreach($array as $key=>$value)
{
echo $value;
if($key != count($array)-1) { echo ", "; }
}
Одним из способов может быть определение того, имеет ли итератор next
. Если к итератору нет следующего, это означает, что вы находитесь в последнем цикле.
foreach ($some_array as $element) {
if(!next($some_array)) {
// This is the last $element
}
}
Если вам нужно что-то сделать для каждого элемента, кроме первого или последнего, и только если в массиве более одного элемента, я предпочитаю следующее решение.
Я знаю, что есть много решений выше и опубликованных за несколько месяцев/за год до моего, но это то, что я считаю довольно элегантным само по себе. Проверка каждого цикла также является логической проверкой, в отличие от числовой проверки "i=(количество-1)", которая может снизить накладные расходы.
Структура цикл может показаться неудобным, но вы можете сравнить его с порядком следования строк (начало), tfoot (конец), tbody (текущий) в тегах таблицы HTML.
$first = true;
foreach($array as $key => $value) {
if ($first) {
$first = false;
// Do what you want to do before the first element
echo "List of key, value pairs:\n";
} else {
// Do what you want to do at the end of every element
// except the last, assuming the list has more than one element
echo "\n";
}
// Do what you want to do for the current element
echo $key . ' => ' . $value;
}
Например, с точки зрения веб-разработки, если вы хотите добавить нижнюю границу к каждому элементу, кроме последнего в неупорядоченном списке (ul), то вместо этого вы можете добавить верхнюю границу к каждому элементу, кроме первого (CSS: первый дочерний элемент, поддерживаемый IE7+ и Firefox/Webkit поддерживает эту логику, тогда как:последний дочерний элемент не является поддерживается IE7).
Вы можете свободно использовать переменную $first для каждого вложенного цикла, и все будет работать просто отлично, так как каждый цикл делает $first ложным во время первого процесса первой итерации (поэтому перерывы/исключения не вызовут проблем).
$first = true;
foreach($array as $key => $subArray) {
if ($first) {
$string = "List of key => value array pairs:\n";
$first = false;
} else {
echo "\n";
}
$string .= $key . '=>(';
$first = true;
foreach($subArray as $key => $value) {
if ($first) {
$first = false;
} else {
$string .= ', ';
}
$string .= $key . '=>' . $value;
}
$string .= ')';
}
echo $string;
Пример вывода:
List of key => value array pairs:
key1=>(v1_key1=>v1_val1, v1_key2=>v1_val2)
key2=>(v2_key1=>v2_val1, v2_key2=>v2_val2, v2_key3=>v2_val3)
key3=>(v3_key1=>v3_val1)
Это должен быть простой способ найти последний элемент:
foreach ( $array as $key => $a ) {
if ( end( array_keys( $array ) ) == $key ) {
echo "Last element";
} else {
echo "Just another element";
}
}
Ссылка: Ссылка
Вы все еще можете использовать этот метод с ассоциативными массивами:
$keys = array_keys($array);
for ($i = 0, $l = count($array); $i < $l; ++$i) {
$key = $array[$i];
$value = $array[$key];
$isLastItem = ($i == ($l - 1));
// do stuff
}
// or this way...
$i = 0;
$l = count($array);
foreach ($array as $key => $value) {
$isLastItem = ($i == ($l - 1));
// do stuff
++$i;
}
У меня сильное ощущение, что в основе этой "проблемы XY" OP хотела просто implode()
функцию.
Поскольку ваше намерение найти массив EOF предназначено только для клея. Познакомьтесь с приведенной ниже тактикой. Вам не нужно требовать EOF:
$given_array = array('column1'=>'value1',
'column2'=>'value2',
'column3'=>'value3');
$glue = '';
foreach($given_array as $column_name=>$value){
$where .= " $glue $column_name = $value"; //appending the glue
$glue = 'AND';
}
echo $where;
O/p:
column1 = value1 AND column2 = value2 AND column3 = value3
Похоже, ты хочешь чего-то подобного:
$array = array(
'First',
'Second',
'Third',
'Last'
);
foreach($array as $key => $value)
{
if(end($array) === $value)
{
echo "last index!" . $value;
}
}
Вы можете выполнить подсчет().
for ($i=0;$i<count(arr);$i++){
$i == count(arr)-1 ? true : false;
}
Или, если вы ищете ТОЛЬКО последний элемент, вы можете использовать end().
end(arr);
Возвращает только последний элемент.
И, как оказалось, вы МОЖЕТЕ индексировать php-массивы целыми числами. Он совершенно доволен
arr[1];
Как насчет использования "конец"? http://php.net/manual/en/function.end.php
Вы также можете сделать что-то вроде этого:
end( $elements );
$endKey = key($elements);
foreach ($elements as $key => $value)
{
if ($key == $endKey) // -- this is the last item
{
// do something
}
// more code
}
Мне вроде как нравится следующее, так как я чувствую, что это довольно аккуратно. Давайте предположим, что мы создаем строку с разделителями между всеми элементами: например, a, b, c
$first = true;
foreach ( $items as $item ) {
$str = ($first)?$first=false:", ".$item;
}
Вот еще один способ, которым вы могли бы это сделать:
$arr = range(1, 10);
$end = end($arr);
reset($arr);
while( list($k, $v) = each($arr) )
{
if( $n == $end )
{
echo 'last!';
}
else
{
echo sprintf('%s ', $v);
}
}
Если я вас понимаю, то все, что вам нужно, это перевернуть массив и получить последний элемент с помощью команды pop:
$rev_array = array_reverse($array);
echo array_pop($rev_array);
Вы также можете попробовать сделать это, чтобы сделать свой запрос... показано здесь со ВСТАВКОЙ
<?php
$week=array('one'=>'monday','two'=>'tuesday','three'=>'wednesday','four'=>'thursday','five'=>'friday','six'=>'saturday','seven'=>'sunday');
$keys = array_keys($week);
$string = "INSERT INTO my_table ('";
$string .= implode("','", $keys);
$string .= "') VALUES ('";
$string .= implode("','", $week);
$string .= "');";
echo $string;
?>
Для сценариев генерации SQL-запросов или всего, что выполняет другое действие для первого или последнего элемента, намного быстрее (почти в два раза быстрее) избежать использования ненужных проверок переменных.
Текущее принятое решение использует цикл и проверку в цикле, которая будет выполняться every_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++;
Небольшой самодельный тест показал следующее:
Тест1: 100000 запусков модели морг
Время: 1869,3430423737 миллисекунд
Тест2: 100000 запусков модели, если последний
Время: 3235,6359958649 миллисекунд
Другой способ - запомнить результат предыдущего цикла цикла и использовать его в качестве конечного результата:
$result = $where = "";
foreach ($conditions as $col => $val) {
$result = $where .= $this->getAdapter()->quoteInto($col.' = ?', $val);
$where .= " AND ";
}
return $this->delete($result);
Я лично использую такую конструкцию, которая позволяет легко использовать элементы html
- И
- : просто измените равенство для другого свойства...
Массив не может содержать ложные элементы, но все остальные элементы, которые преобразуются в логическое значение false.
$table = array( 'a' , 'b', 'c'); $it = reset($table); while( $it !== false ) { echo 'all loops';echo $it; $nextIt = next($table); if ($nextIt === false || $nextIt === $it) { echo 'last loop or two identical items'; } $it = $nextIt; }
Вы можете быстро получить последний индекс по:
$numItems = count($arr);
echo $arr[$numItems-1];
<?php foreach($have_comments as $key => $page_comment): ?>
<?php echo $page_comment;?>
<?php if($key+1<count($have_comments)): ?>
<?php echo ', '; ?>
<?php endif;?>
<?php endforeach;?>
Вот мое решение: Просто получите количество вашего массива минус 1 (так как они начинаются с 0).
$lastkey = count($array) - 1;
foreach($array as $k=>$a){
if($k==$lastkey){
/*do something*/
}
}
foreach ($array as $key => $value) {
$class = ( $key !== count( $array ) -1 ) ? " class='not-last'" : " class='last'";
echo "<div{$class}>";
echo "$value['the_title']";
echo "</div>";
}
У меня есть обобщенное решение, которое я использую для общей цели компиляции строки из массива строковых значений. Все, что я делаю, это добавляю необычную строку в конец, а затем заменяю ее.
Функция для возврата строки из массива, разделенной, без конечного разделителя:
function returnArraySeparated($aArr, $sSep, $sAdd = "@X@") {
$strReturn = (string) "";
# Compile the set:
foreach ($aArr as $sItem) {
$strReturn .= $sItem . $sSep;
}
# Easy strip the end:
$strReturn = str_replace($sSep . $sAdd, "", $strReturn . $sAdd);
return $strReturn;
}
Ничего особенного, но это работает:)