Monday, April 25, 2011

How do you find the last element of an array while iterating using a foreach loop in php ?

I am writing a sql query creator using some parameters. While doing that ,I came across this problem. In java , Its very easy to detect the last element of an array from inside the for loop by just checking the current array position with the array length.

for(int i=0; i< arr.length;i++){

     boolean isLastElem = i== (arr.length -1) ? true : false;        

}

php has some different fashion. They have non integer indexes to access arrays. So you must iterate over an array using foreach loop. But it becomes very problematic when you need to take some decision (in my case to append or/and parameter while building query).

I am sure there must be some standard way of doing this.

How do you solve this problem normally in php ?

From stackoverflow
  • you can do a count().

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

    or if you're looking for ONLY the last element, you can use end().

    end(arr);
    

    returns only the last element.

    and, as it turns out, you CAN index php arrays by integers. It's perfectly happy with

    arr[1];
    
  • It sounds like you want something like this:

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

    That being said, you don't -have- to iterate over an "array" using foreach in php.

    Vaibhav Kamble : I think I will go for this solution as it is almost similar to the code I posted. Even Jeremy's answer is well fit but I think it got little complex compared to this one. I have not ran any tests but I guess this answer shall be faster as it is not extracting array of keys.This shall have O(1) speed
    Paul Sheldrake : Shouldn't $i = 1 because Count starts at 1 and not 0?
  • You could get the value of the last key of the array using end(array_keys($array)) and compare it to the current key:

    $last_key = end(array_keys($array));
    foreach ($array as $key => $value) {
        if ($key == $last_key) {
            // last element
        } else {
            // not last element
        }
    }
    
    Patrick Daryll Glandien : +1 I agree - the other solutions rely on the array having numeric indexes.
    Richard Levasseur : In my own defense, my answer doesn't rely on the array having numeric keys :)
    OIS : string comparison is slower then integers, and not always accurate when comparing strings to integers (you should at least have used ===). Im voting this down.
  • You can still use that method with associative arrays:

    $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;
    }
    
  • $toEnd = count($arr);
    foreach($arr as $key=>$value) {
      if (0 === --$toEnd) {
        echo "last index! $value";
      }
    }
    

    or the best way is probably this if you still execute the other loop code

    foreach($arr as $key=>$value) {
      //something
    }
    echo "last index! $key => $value";
    
    Sohnee : In this example, it will perform the --$toEnd in every iteration in the loop, so I would recommend moving that outside of the foreach loop so you can perform a direct comparison on an already calculated value.
    OIS : Of course it will perform the --$toEnd for every iteration, thats the point. If I moved it outside the loop, it would not work anymore.
  • You could also do something like this:

    $endKey = key(end( $elements ));
    foreach ($elements as $key => $value)
    {
         if ($key == $endKey) // -- this is the last item
         {
              // do something
         }
    
         // more code
    }
    
    OIS : end returns the value not the array, so the way you made it doesnt work. string comparison is also slower then integer.
    KOGI : You are right. it should be end($elements); $endKey = key($elements);
  • no your all wrong its this

    public boolean add(int num) {
    int index = data.length; if(index < this.count) { data[index +1] = num; return true;

  • Here's another way you could do it:

    $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);
        }
    }
    
  • why so complicated?

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

    This will add a , behind every value except the last one!

  • If you need to do something for every element except either the first or the last and only if there is more than one element in the array, I prefer the following solution.

    I know there are many solutions above and posted months/one year before mine, but this is something I feel is fairly elegant in its own right. The check every loop is also a boolean check as opposed to a numeric "i=(count-1)" check, which may allow for less overhead.

    The structure of the loop may feel awkward, but you can compare it to the ordering of thead (beginning), tfoot (end), tbody (current) in HTML table tags.

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

    For instance, in web development terms, if you want to add a border-bottom to every element except the last in an unordered list (ul), then you can instead add a border-top to every element except the first (the CSS :first-child, supported by IE7+ and Firefox/Webkit supports this logic, whereas :last-child is not supported by IE7).

    You can feel free to reuse the $first variable for each and every nested loop as well and things will work just fine since every loop makes $first false during the first process of the first iteration (so breaks/exceptions won't cause issues).

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

    Example output:

    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)
    
  • Hi, If I understand you, then all you need is to reverse the array and get the last element by a pop command:

       $rev_array = array_reverse($array);
    
       echo array_pop($rev_array);
    
  • How about using "end"? http://php.net/manual/en/function.end.php

0 comments:

Post a Comment