3

I have a foreach that iterates between items in a array to build an excel file. I want to place a total row after each item in the array if the next element in the array matches a specific condition (has a specific value in one key). So I want to use next() to check that value but as far as I know and for what I read here using next I'll move the pointer to the next row and the answer was to use current. How can I see the next item in the array without moving the pointer? reading that question I have written this:

foreach($creds as $cred){
    echo $cred['tipo'];
    //if the next item has a 'tipo' key with a specific value
    if(current($creds['tipo'])!='4'){
        echo 'Total';
    }
}

but this is not working. How to fix it?

EDIT: based on the answers I will move the echo 'Total' stuff at the beginning of the next iteration instead of at the bottom of the current iteration. There are no other solutions using foreach as far as I see in the answers

10
  • Unsure, but =='4' is looking for a string, rather than a possible integer ==4. Commented Jan 16, 2016 at 14:54
  • how about for($x = 0; $x < count($creds); $x++) { if(($x+1 < count($x)) && current($creds[$x + 1]['tipo']) == '4') { echo 'Total'; } } ? Commented Jan 16, 2016 at 14:55
  • @Fred-ii- actually the real code is looking for a string (some letters). Commented Jan 16, 2016 at 14:57
  • 1
    si Lelio, grazie! piano... non veloce ma "not too shabby" ;-) Commented Jan 16, 2016 at 15:02
  • 1
    There is nothing preventing you from using a separate array iterator that you can play with in any way that you wish inside the foreach loop. Outside the foreach loop do: $iter = new \ArrayIterator($cred). Inside the loop, ensure the foreach loop and the $iter stay in step i,e do next() at the end of the loop. Where it gets useful is that you can do next() and prev() on the $iter all you want. The foreach will not know or care. Commented Jan 16, 2016 at 16:39

4 Answers 4

2

The requirement is:

  • inside a foreach loop to look at the next value or key but not change the position of the current iterator pointer of the foreach loop.

Although it is more code, one way it to create a completely separate iterator on the same array.

This new iterator has to be kept in step with the foreach loop but that is quite simple to do.

The advantage is that you can manipulate any way you wish using next(), prev(), current() etc. and know that the foreach loop will not be affected.

For this example where the requirement is to test the next entry ahead of th current one. It is worthwhile just starting with the iterator pointing to the second entry and just advance each time.

Example, untested code...

$iter = new \ArrayIterator($cred)s; // mirror of the `foreach` loop 

iterator foreach($creds as $cred) {

    // get next key and value...
    $iter->next(); 
    $nextKey = $iter->key();
    $nextValue = $iter->current();

    echo $cred['tipo'];

    // if the next item has a 'tipo' key with a specific value
    if($nextValue['tipo']) != '4'){
        echo 'Total';
    }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Try this code

$keys = array_keys($creds);

for($i = 0; $i < sizeof($keys); $i++)
{
    echo $creds[$keys[$i]] .' ';

    //$creds[$keys[$i+1]] - next item

    if($keys[$i+1] == 'tipo' && $creds[$keys[$i+1]] == 4 )
    {
        //
    }
}

2 Comments

thanks! This is a valid workaround but I am looking to learn how to have a preview of next item in an array without moving the pointer in a foreach loop.
$next = $creds[next($keys)] this next value
0

I'd check in each loop if the current item has your special key/value pair and then one more time at the end. This way you don't have to access the next item (and move the pointer forth and back). If it's more complicated than echo 'Total'; then you could wrap it into a function, to avoid code duplication in and after the foreach loop.

$creds = [
    ['tipo' => '1'],
    ['tipo' => '2'],
    ['tipo' => '3'],
    ['tipo' => '4'],
    ['tipo' => '5'],
];

foreach ($creds as $cred) {
    if ($cred['tipo'] == '4') {
        echo "Total\n";
    }
    echo $cred['tipo'] . "\n";
}
// If the very last row had the special key, print the sum one more time
if ($cred['tipo'] == '4') {
    echo "Total\n";
}


/* Output:
1
2
3
Total
4
5
*/

Edit:

I misinterpreted your requirement ("I want to place a total row after each item in the array if the next element in the array matches a specific condition"). If you want it the other way round, I'd suggest, to "buffer" the value of the current row in a variable $previous_row, until the foreach loop moves the pointer forward and you are able to access and check the value:

$creds = [
    ['tipo' => '1'],
    ['tipo' => '2'],
    ['tipo' => '3'],
    ['tipo' => '4'],
    ['tipo' => '5'],
];

$previous_row = '';
foreach ($creds as $cred) {
    echo $previous_row;
    if ($previous_row && $cred['tipo'] != '4') {
        echo "Total\n";
    }
    $previous_row = $cred['tipo'] . "\n";
}
// If the very last row had the special key, print the sum one more time
echo $previous_row;
if ($cred['tipo'] != '4') {
    echo "Total\n";
}


/* Output:
1
Total
2
Total
3
4
Total
5
Total
*/

4 Comments

sorry but this code is checking the actual row but I want to echo 'Total' after the current row if the NEXT row as 4 as value for the key 'tipo'
@LelioFaieta, I've made a small edit. It's correct, that the current item is checked for value 4, but before the regular line output, which means, it happens after the previous line.
the result should be 1 Total, 2 Total, 3 4 Total, 5 Total. It should skip total on 3 because the next item is 4
I've changed it around now in the "Edit". Using a for loop would most probably be a bit more elegant, but I kept a foreach just to demonstrate a possible solution.
0

You can try using prev function after using next. It might be not be the best solution but it should work.

$values = array(1,2,3);

foreach ($values as $a) {
    print next($values);
    prev();
}

should output 2,3

EDIT

Actually next() is not affecting your loop key after execution and gives you right next value. It is also noticed in answer to link you provided. Also you can change iterations manually using custom iterator and prev function. http://php.net/manual/en/language.oop5.iterations.php

<?php
class MyIterator implements Iterator
{
    private $var = array();

    public function __construct($array)
    {
       if (is_array($array)) {
            $this->var = $array;
    }
}

public function rewind()
{
    reset($this->var);
}

public function current()
{
    $var = current($this->var);

    return $var;
}

public function key() 
{
    $var = key($this->var);
    return $var;
}

public function next() 
{
    $var = next($this->var);
    return $var;
}

public function prev()
{
    $var = prev($this->var);
    return $var;
}

public function valid()
{
    $key = key($this->var);
    $var = ($key !== NULL && $key !== FALSE);
    return $var;
}

}

$values = array(1,2,3);
$it = new MyIterator($values);

foreach ($it as $a => $b) {
   print 'next is '.$it->next();
   $it->prev();
}
?>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.