2

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

Community
  • 1
  • 1
Lelio Faieta
  • 6,457
  • 7
  • 40
  • 74
  • Unsure, but `=='4'` is looking for a string, rather than a possible integer `==4`. – Funk Forty Niner Jan 16 '16 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'; } } ? – Mike Kor Jan 16 '16 at 14:55
  • @Fred-ii- actually the real code is looking for a string (some letters). – Lelio Faieta Jan 16 '16 at 14:57
  • @MikeKor thanks, I know how to use for but I'd like to learn how to use next and current in a foreach too. :) – Lelio Faieta Jan 16 '16 at 14:57
  • *bene*, no problema Lelio. – Funk Forty Niner Jan 16 '16 at 14:59
  • 1
    si Lelio, grazie! piano... non veloce ma "not too shabby" ;-) – Funk Forty Niner Jan 16 '16 at 15:02
  • similar problem http://stackoverflow.com/questions/20479610/php-array-get-next-key-value-in-foreach – Mike Kor Jan 16 '16 at 15:04
  • @MikeKor yes, this is another workaround and was used because the user was looking for the next two items (not only the first one after). I want to use next because my code is much more complicated than the example one and I cannot rewrite it to use keys! – Lelio Faieta Jan 16 '16 at 15:07
  • 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. – Ryan Vincent Jan 16 '16 at 16:39
  • @RyanVincent very good point! This is actually the closest solution to the issue. Will you turn the comment into an answer so I can flag it as solved? – Lelio Faieta Jan 16 '16 at 16:41

4 Answers4

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';
    }
}
Ryan Vincent
  • 4,483
  • 7
  • 22
  • 31
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 )
    {
        //
    }
}
AkimBB
  • 11
  • 3
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
*/
Nick
  • 2,576
  • 1
  • 23
  • 44
  • 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' – Lelio Faieta Jan 16 '16 at 15:04
  • @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. – Nick Jan 16 '16 at 15:13
  • 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 – Lelio Faieta Jan 16 '16 at 15:15
  • 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. – Nick Jan 16 '16 at 15:30
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();
}
?>
Community
  • 1
  • 1
Mike Kor
  • 876
  • 5
  • 14