4

Trying to delete all elements in the array (given below) which are less then 0 using the following code:

 <?php 
       $arr=array(1,2,3,4,5,-6,-7,-8,-9,-10);

        for ($i=0;$i<count($arr);$i++){
                if ($arr[$i]<0) {
                unset($arr[$i]);
                }
        }

    var_dump($arr);

    echo '<pre>', print_r($arr), '</pre>';

    ?>

However, the result is the following:

array(7) { [0]=> int(1) [1]=> int(2) [2]=> int(3) [3]=> int(4) [4]=> int(5) [8]=> int(-9) [9]=> int(-10) }
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [8] => -9
    [9] => -10
)
1

Quite confused why not all the elements which are less then 0 are removed from the array. Any thoughts on this?

1
  • 1
    You should accept an answer if it solved your issue. Commented Feb 15, 2018 at 14:23

6 Answers 6

4

This is what usually happens when you remove elements while iterating forwards through a collection. You end up missing elements because you're trying to iterate a moving target. One solution would be to iterate backwards

for ($i = count($arr) - 1; $i >= 0; $i--)

Another would be to simply use array_filter to create a new array

$newArr = array_filter($arr, function($num) {
    return $num >= 0;
});
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much for the appropriate post!
4

If you really need to do it in a loop, you can avoid that problem by using a foreach loop instead.

foreach ($arr as $key => $value) {
    if ($value < 0) {
        unset($arr[$key]);
    }
}

Removing elements as you iterate shouldn't cause any problems this way.

2 Comments

Surprised this doesn't suffer from the same problem. Nice one
foreach makes a copy of the array to iterate.
3

You are iterating using count($arr) which is reevaluated after each iteration. Since you remove an item, the array gets shorter. At the same time you increment your iterator. This works out until you reach the second last item, where deleting that item and increment the counter makes the loop condition false, thus skipping the last elements.

You can do an echo in the loop to print $i and count($arr) to see the details.

Comments

2

This is because you are manipulating the array while you are positively iterating through it, which can make it off-set and skip elements. One common way to solve this is to do the loop backwards:

   $arr=array(1,2,3,4,5,-6,-7,-8,-9,-10);

    for ($i=count($arr)-1;$i>=0;$i--){
            if ($arr[$i]<0) {
            unset($arr[$i]);
            }
    }

var_dump($arr);

echo '<pre>', print_r($arr), '</pre>';

2 Comments

to Phil: Hmmm... count($arr) returns 10 in this case, so $i=count($arr)-1 produces 9. therefore, $i runs down from 9 till 0. All the elements are engaged. Am I under the wrong impression?
@Sam It's because I missed the >= in $i>0, which I edited to $i>=0 after the comment.
2

You could do this using array_filter(). The second parameter is an anonymous function that takes as argument an element of the array. Inside, you have to determine weither it should be kept or not.

$arr=array(1,2,3,4,5,-6,-7,-8,-9,-10);
$arr = array_filter($arr, function($e) {
    return $e >= 0 ; // keep only element greater than zero
});
echo '<pre>', print_r($arr), '</pre>';

Outputs :

array(5) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
}

1 Comment

Elegant way of solving the issue. Thank you!
2

Adding to the excellent foreach and array_filter answers (which detail the issue), using your existing loop, just count first so that it can't change each iteration:

$arr=array(1,2,3,4,5,-6,-7,-8,-9,-10);

$c = count($arr);

for ($i=0; $i<$c; $i++){
    if ($arr[$i]<0) {
        unset($arr[$i]);
    }
}

3 Comments

Good advice in general for for loop iterating.
Nice anwser too :) Maybe a better choice for large arrays. Doesn't create function or copy of variables.
Just applied this before saw this answer. Thank you so much for notice.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.