============= count=".count($" /> ============= count=".count($" /> ============= count=".count($"/>

why is array-item unset only limited working?

52 Views Asked by At

I tried to unset all records smaller than 60, but every time only a limited number were unset. Here is my code:

echo "<p>============= count=".count($ar); // 1764
for ($i=0;$i<count($ar);++$i) 
    if ((strlen($ar[$i])<60) OR (strpos($ar[$i],'src=')<5)) 
        unset ($ar[$i]);

$ar=array_values($ar); // renumber the indices

echo "<p>============================= count=".count($ar); 
//    1452; OK, so they are all larger than 60 chars, right?
for ($i=0;$i<count($ar);++$i) 
    if (strlen($ar[$i])<60) 
        echo"<br>$i - ".$ar[$i]; // not so; several items printed!!! ???

for ($i=0;$i<count($ar);++$i) 
    if (strlen($ar[$i])<60) 
        unset ($ar[$i]); //again

$ar=array_values($ar);
echo "<p>============================= count=".count($ar); // 1396; OK, now all are larger than 60 chars?

for ($i=0;$i<count($ar);++$i) 
    if (strlen($ar[$i])<60) 
        echo"<br>$i - ".$ar[$i]; // no, still items printed!!! ???

for ($i=0;$i<count($ar);++$i) 
    if (strlen($ar[$i])<60) 
        unset ($ar[$i]);

$ar=array_values($ar);
echo "<p>============================= count=".count($ar); //  1386; so 10 more were removed; are we done now?
for ($i=0;$i<count($ar);++$i) 
    if (strlen($ar[$i])<60) 
        echo"<br>$i - ".$ar[$i]; // again still items printed!!! ???

How is it possible that after every loop and removal of items less than 60 chars, there are still array-items not unset that will be unset at a next repeat? I am really at my wits end. What did I do wrong? Can somebody explain, please. Thanks....Eke

3

There are 3 best solutions below

0
user2182349 On

Use a foreach loop - https://www.php.net/manual/en/control-structures.foreach.php

The issue is that the number of elements in the array is changing on the loop iterations when items are being removed.

A better approach is to use array_filter - https://www.php.net/manual/en/function.array-filter.php

<?php

$arrOriginal = [ 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten'];

$arr = $arrOriginal;
for ($i = 0; $i < count($arr); $i++) {
        echo '$i = '.$i.' $arr[$i] = '.$arr[$i].' and count($arr) = '.count($arr).PHP_EOL;
        if (strlen($arr[$i]) < 4) {
                unset($arr[$i]);
        }
}
var_dump($arr);

$arr = $arrOriginal;
foreach ($arr as $k => $v) {
        echo '$k = '.$k.' $arr[$k] = '.$arr[$k].' and count($arr) = '.count($arr).PHP_EOL;
        if (strlen($arr[$k]) < 4) {
                unset($arr[$k]);
        }
}
var_dump($arr);

$arr = $arrOriginal;
$arr = array_filter($arr, function ($v) {
        return strlen($v) >= 4;
});
var_dump($arr);
1
RiggsFolly On

Each time you find a row to unset, you reduce the size of the array you are processing, by one occurance. And because you have the loop control using count($ar) each time round the loop you recalc the terminating condition based on the new size of the array (after removing a occurance) so basically you never process all the occurances of the array.

All you need to do is calc the array size once outside the loop control code

$max = count($ar);
for ($i=0; $i<$max; ++$i) {
    if ((strlen($ar[$i])<60) OR (strpos($ar[$i],'src=')<5)) {
        unset ($ar[$i]);
    }
}
1
Eke On

Thank you for your help, you solved my puzzle.

Indeed my error was to use count($ar) inside the loop where I reduced the size of the array so count($ar) was reduced after each unset, leaving one potential array-item in the tail of the array not to be inspected. This also explains why after each loop the remaining items (smaller than 60 but surprisingly not unset) were in the "tail" of the array. Thanks again for giving me this insight........Eke