2009-03-20 3 views
166

Я пишу создатель SQL-запросов, используя некоторые параметры. В Java очень легко обнаружить последний элемент массива из цикла for, просто проверив текущую позицию массива с длиной массива.Найти последний элемент массива при использовании цикла foreach в PHP

for(int i=0; i< arr.length;i++){ 
    boolean isLastElem = i== (arr.length -1) ? true : false;   
} 

В PHP у них есть нецелые индексы для доступа к массивам. Таким образом, вы должны выполнять итерацию по массиву с использованием цикла foreach. Это становится проблематичным, когда вам нужно принять какое-то решение (в моем случае добавить или/и параметр при построении запроса).

Я уверен, что для этого должен быть стандартный способ.

Как вы решаете это на PHP?

+2

. Вы пытаетесь определить, следует ли вам конкатрировать «И» или «ИЛИ» между части предложения where? –

+1

, просто указывая, что вы должны хранить общее количество в переменной вместо вызова метода для каждой итерации. for (int i = 0, int t = arr.length; i OIS

+0

http://stackoverflow.com/questions/156650/does-the-last-element-in-a-loop-deserve-a-separate-treatment – xtofl

ответ

240

Это звучит, как вы хотите что-то вроде этого:

$numItems = count($arr); 
$i = 0; 
foreach($arr as $key=>$value) { 
    if(++$i === $numItems) { 
    echo "last index!"; 
    } 
}  

Это, как говорится, не -have- перебрать «массив», используя foreach в PHP.

+0

Я думаю, что поеду за этим решением, поскольку оно почти похоже на код, который я опубликовал. Даже ответ Джереми хорошо подходит, но я думаю, что он был немного сложным по сравнению с этим. У меня не было никаких тестов, но я думаю, что этот ответ должен быть быстрее, так как он не извлекает массив ключей. Это должно иметь скорость O (1) –

+31

Не должно быть $ i = 1, потому что граф начинается с 1, а не 0? –

+0

hah, ничего себе, исправил это. thanks :) –

1

вы можете сделать счетчик().

for ($i=0;$i<count(arr);$i++){ 
    $i == count(arr)-1 ? true : false; 
} 

или если вы ищете ТОЛЬКО последний элемент, вы можете использовать end().

end(arr); 

возвращает только последний элемент.

и, как оказалось, вы МОЖЕТЕ индексировать php-массивы целыми числами. Это совершенно доволен

arr[1]; 
+1

Недостаток в end (arr) заключается в том, что он устанавливает внутренний указатель массива на последний элемент. – Vijay

+0

Нет, вы ** НЕ ДОЛЖНЫ ** использовать целые числа для доступа к массивам, если не знаете, что ключи являются числовыми и последовательными. Рассмотрим: '$ a = array (0 => 'A', 2 => 'B', 'aaa' => 'C')'. Что вы получаете, если имеете доступ к '$ a [count ($ a) -1]'? – johndodo

172

Вы можете получить значение последнего ключа массива с помощью 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 
    } 
} 
+1

+1 Я согласен - другие решения полагаются на массив с числовыми индексами. –

+18

В моей собственной защите мой ответ не полагается на массив с числовыми ключами :) –

+2

Сравнение строк медленнее, чем целые числа, и не всегда точны при сравнении строк с целыми числами (вы должны хотя бы использовать ===). Я голосовал за это. – OIS

3

Вы все еще можете использовать этот метод с ассоциативными массивами:

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

Пожалуйста, измените $ key = $ array [$ i]; $ key = $ keys [$ i]; в первом цикле. – Narek

20

Когда 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); 
+2

Конечно, для каждой итерации будет выполняться значение - $ toEnd. Если бы я переместил его за пределы цикла, это больше не сработало. – OIS

+0

@razorfish Wtf? Редактирование кода не имело смысла ... – OIS

+0

Спасибо большое, ты спас меня ... – aidadev

1

Вы также могли бы сделать что-то вроде этого:

end($elements); 
$endKey = key($elements); 
foreach ($elements as $key => $value) 
{ 
    if ($key == $endKey) // -- this is the last item 
    { 
      // do something 
    } 

    // more code 
} 
+0

end возвращает значение не массивом, поэтому способ, которым вы его сделали, не работает. сравнение строк также медленнее, чем целое. – OIS

+0

Вы правы. он должен быть конечным ($ element); $ endKey = key ($ elements); – KOGI

0

Вот еще один способ, которым вы могли бы сделать это:

$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); 
    } 
} 
32

почему так сложно?

foreach($input as $key => $value) { 
    $ret .= "$value"; 
    if (next($input)==true) $ret .= ","; 
} 

Это добавит позади каждого значения, кроме последнего!

+2

Нет, если следующий $ input содержит логическое значение false, что является серьезной проблемой для next(). – soulseekah

+22

Если я ошибаюсь, это не работает, потому что вызов next() продвигает указатель массива, поэтому вы пропускаете все остальные элементы цикла. –

+2

Кажется, не работает для меня. Второй последний элемент не получает запятую, но должен. – zuallauz

4

Если вам нужно что-то сделать для каждого элемента, кроме первого или последнего, и только в том случае, если в массиве имеется более одного элемента, я предпочитаю следующее решение.

Я знаю, что существует много решений выше и размещено месяцев/за год до моего, но это то, что я чувствую, достаточно элегантно. Проверка каждого цикла также является логической проверкой, в отличие от числовой проверки «i = (счет-1)», что может позволить уменьшить накладные расходы.

Структура петли может показаться неудобной, но вы можете сравнить ее с упорядочением тегов (начало), tfoot (end), tbody (current) в тегах 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; 
} 

Например, с точки зрения веб-разработки, если вы хотите добавить границы дна к каждому элементу, за исключением последнего в неупорядоченном списке (ул), то вместо этого можно добавить пограничную-топ для каждого элемента, кроме первого (CSS: first-child, поддерживаемый IE7 + и Firefox/Webkit, поддерживает эту логику, тогда как последний-последний не поддерживается IE7).

Вы можете свободно повторно использовать переменную $ first для каждого вложенного цикла, и все будет работать нормально, поскольку каждый цикл делает первый первый ложь во время первого процесса первой итерации (так что breaks/exceptions won ' не вызывают проблем).

$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) 
+0

Thanx, это мое любимое решение! Он очень гибкий и стоит только логический. BTW, я думаю, что это будет работать для массива, содержащего * как минимум * один элемент тоже (не только * больше, чем * один элемент). –

0

Если я вас понимаю, то все, что вам нужно, чтобы изменить массив и получить последний элемент командой поп:

$rev_array = array_reverse($array); 

    echo array_pop($rev_array); 
+0

Этот всплывающий исходный первый элемент ... – OIS

0

Вы также могли бы попытаться это сделать запрос ... показанный здесь с вкладышем

<?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; 
?> 
0

Для 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++; 

Немного самодельный тест показал следующий :

test1: 100000 прогоны модели Morg

время: 1869.3430423737 миллисекунды

test2: 100000 бежит модели, если последний

время: 3235.6359958649 миллисекунды

2

Это звучит, как вы хотите что-то вроде этого:

$array = array(
    'First', 
    'Second', 
    'Third', 
    'Last' 
); 

foreach($array as $key => $value) 
{ 
    if(end($array) === $value) 
    { 
     echo "last index!" . $value; 
    } 
} 
+2

Использование значения обычно не является хорошей идеей, поскольку оно не будет работать должным образом, если массив имеет два одинаковых значения. – orrd

17

Есть уже много ответов, но это стоит посмотреть в итераторы, а также, особенно в том виде, в каком его запросили стандартный способ:

$arr = range(1, 3); 

$it = new CachingIterator(new ArrayIterator($arr)); 
foreach($it as $key => $value) 
{ 
    if (!$it->hasNext()) echo 'Last:'; 
    echo $value, "\n"; 
} 

Возможно, вы обнаружили что-то такое более гибкая и для других случаев.

+0

Просто красиво. – Tek

-3

У меня есть обобщенное решение, которое я использую для общей цели компиляции строки из массива строковых значений. Все, что я делаю, это добавить необычную строку в конец, а затем заменить ее.

Функция возвращает строку из массива, разделенные, без ведомой сепаратора:

function returnArraySeparated($aArr, $sSep, $sAdd = "@[email protected]") { 

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

Ничего особенного, но она работает :)

+3

Итак, вы изобрели implode()? –

0

Другой путь должен помнить предыдущий и в конечном итоге:

$result = $where = ""; 
    foreach ($conditions as $col => $val) { 
     $result = $where .= $this->getAdapter()->quoteInto($col.' = ?', $val); 
     $where .= " AND "; 
    } 
    return $this->delete($result); 
0

Я лично использую такую ​​конструкцию, которая enab le легко использовать с html < ul> и < li> элементы: просто измените равенство для другого свойства ...

Массив не может содержать ложные элементы, но все остальные элементы, которые вставляются в ложное булево.

$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; 
} 
6

Таким образом, если массив имеет уникальные значения массива, то определение последней итерации тривиальна:

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!'; 
} 

Также обратите внимание на строгого оператора соприкосновения, что весьма важно в этом случае.

+0

Это довольно неэффективный способ. –

+0

Nope. Это не. end() выполняет O (1). Он также короче, чем другие решения, и он хорошо читается -> Если элемент равен концу массива, напишите «Last». –

+0

Это более чем в два раза медленнее моего первого и последнего примеров для 100000 значений. – OIS

3

У меня есть сильное чувство, что в основе этой «проблемы XY» OP хотел только функцию implode().

+1

true. Есть случаи, когда implode просто не так практичен. Представьте себе, например, попытку взорвать длинную строку html с лотами динамических переменных в нем. Конечно, вы могли бы сделать ob_start/ob_get_clean на нем или просто построить его как $ str = '...'. Но бывают случаи, когда это можно считать просто излишним переполнением –

0

Вы можете dirctly получить последний индекс по:

$numItems = count($arr);

echo $arr[$numItems-1];

5

Если у вас есть массив, хранящийся в переменной ...

foreach($array as $key=>$value) 
{ 
    echo $value; 
    if($key != count($array)-1) { echo ", "; } 
} 
+0

Это очень просто и полезно. Я бы только считал массив первым за пределами цикла foreach, так что программе не приходилось подсчитывать каждый раз, когда функция foreach оценивает каждый элемент. – Pathros

+3

Это не будет работать на ассоциативных массивах. $ key - не всегда число. – Jonathan

0
<?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;?> 
+0

Он работает только тогда, когда ключи являются числовыми и в порядке. – Alekc

3

Как ваш Намерение найти массив 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; 

о/р:

column1 = value1 AND column2 = value2 AND column3 = value3 
1

Я вроде как следующее, как я чувствую, что это довольно аккуратно. Предположим, мы создаем строку с разделителями между всеми элементами: например. а, б, в

$first = true; 
foreach ($items as $item) { 
    $str = ($first)?$first=false:", ".$item; 
} 
4

Это должно быть легкий способ найти последний элемент:

foreach ($array as $key => $a) { 
    if (end(array_keys($array)) == $key) { 
     echo "Last element"; 
    } else { 
     echo "Just another element"; 
    } 
} 

Ссылка: Link

+0

- сломанная ссылка - – T30

0

Вот мое решение: Просто получить количество вашего массива , минус 1 (начиная с 0).

$lastkey = count($array) - 1; 
foreach($array as $k=>$a){ 
    if($k==$lastkey){ 
     /*do something*/ 
    } 
} 
2

Одним из способов может быть, чтобы обнаружить, если итератор имеет next. Если на итераторе нет следующего, это означает, что вы находитесь в последнем цикле.

foreach ($some_array as $element) { 
    if(!next($some_array)) { 
     // This is the last $element 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^