skip to Main Content

As part of a larger project, I’m receiving arrays in a form similar to this:

$out = array(
        '2011' => ['Out', 'arrv'],
        '2012' => ['Out'],
        '2013' => ['Out'],
        '2014' => ['Out'],
        '2015' => ['Out'],
        '2016' => ['some', 'none', 'test'],
        '2017' => ['Out'],
        '2018' => ['Out'],
        '2019' => ['Out'],
        '2020' => ['Out', 'did'],
        '2021' => ['Out'],
        '2022' => ['Out'],
        '2023' => ['Out', 'did']
);

I need to remove the consecutive "Out" lines, but keep the first and the last. My failed attempt:

foreach ($out as $dtp=>$dto) {
    if (count($dto) == 1) {
        if (str_contains($dto[0], "Out")) {
            $idx = array_search($dtp, array_keys($out));
            echo "$dtp contains the string; index is $idx" . PHP_EOL;
            var_dump($out[intval(array_keys($idx - 1))]);
            if ((str_contains($out[$idx-1][0], "Out")) && (str_contains($out[$idx+1][0], "Out")) && count($out[$idx-1] == 1) &&  count($out[$idx+1] == 1)) {
                array_splice($out, $idx, 1);
            }
        }
    }
}

Counts are there since there may be multiple events per timestamp. Echo returns the correct index number, but var_dump always returns NULL.

Current debugging output:

2017 contains the string; index is 6
PHP Warning:  array_keys() expects parameter 1 to be array, integer given in /home/redacted/pub/dbg2.php on line 28
PHP Notice:  Undefined offset: 0 in /home/redacted/pub/dbg2.php on line 28
NULL
2018 contains the string; index is 7
PHP Warning:  array_keys() expects parameter 1 to be array, integer given in /home/redacted/pub/dbg2.php on line 28
PHP Notice:  Undefined offset: 0 in /home/redacted/pub/dbg2.php on line 28
NULL
2019 contains the string; index is 8
PHP Warning:  array_keys() expects parameter 1 to be array, integer given in /home/redacted/pub/dbg2.php on line 28
PHP Notice:  Undefined offset: 0 in /home/redacted/pub/dbg2.php on line 28
NULL
2021 contains the string; index is 10
PHP Warning:  array_keys() expects parameter 1 to be array, integer given in /home/redacted/pub/dbg2.php on line 28
PHP Notice:  Undefined offset: 0 in /home/redacted/pub/dbg2.php on line 28
NULL
2022 contains the string; index is 11
PHP Warning:  array_keys() expects parameter 1 to be array, integer given in /home/redacted/pub/dbg2.php on line 28
PHP Notice:  Undefined offset: 0 in /home/redacted/pub/dbg2.php on line 28
NULL

While I haven’t shared the full source code, the output from the array would be something like this:

2011: Out
2011: arrv
2012: Out
2015: Out
2016: some
2016: none
2016: test
2017: Out
2019: Out
2020: Out
2020: did
2021: Out
2022: Out
2023: Out
2023: did

2

Answers


  1. Please note that your sample output array has duplicated keys, which I think, is not allowed. Try this:

    <?php
    
    $out = [
        '2011' => ['Out', 'arrv'],
        '2012' => ['Out'],
        '2013' => ['Out'],
        '2014' => ['Out'],
        '2015' => ['Out'],
        '2016' => ['some', 'none', 'test'],
        '2017' => ['Out'],
        '2018' => ['Out'],
        '2019' => ['Out'],
        '2020' => ['Out', 'did'],
        '2021' => ['Out'],
        '2022' => ['Out'],
        '2023' => ['Out', 'did']
    ];
    
    $cleaned_out = [];
    $first = true;
    $last_key = null;
    $last_value = null;
    $key = null;
    $value = null;
    $printed_last_key = false;
    
    foreach ($out as $key => $values) {
        foreach ($values as $value) {
            if ($first) {
                $last_key = $key;
                if ($value == 'Out') {
                    $first = false;
                }
                echo $key . ' ' . $value . PHP_EOL;
                $printed_last_key = true;
            } else {
                if ($value == 'Out') {
                    $last_key = $key;
                    $last_value = $value;
                    $printed_last_key = false;
                } else {
                    if (!$printed_last_key) {
                        echo $last_key . ' ' . $last_value . PHP_EOL;
                    }
                    echo $key . ' ' . $value . PHP_EOL;
                    $cleaned_out[$last_key] = $last_value;
                    $cleaned_out[$key] = $value;
                    $first = true;
                    $printed_last_key = true;
                }
            }
        }
    }
    
    ?>
    
    Login or Signup to reply.
  2. I’ll ignore the error

    array_keys() expects parameter 1 to be array, integer given

    because it’s only outputting some debugging information; what you need to resolve is the logic used to detect the "islands" in your sequence of years.

    This code is not elegant, won’t work for all combinations of the data, and doesn’t split up the array data – as that’s not the issue here – but hopefully it will help you:

    $result = [];
    $inSequence = false;
    $prev = null;
    
    foreach ($out as $year => $data) {
      if (str_contains($data[0], "Out")) {
        if (!$inSequence) {
          $result[$year] = $data; // Save first of sequence
          $inSequence = !$inSequence; // toggle as in sequence
        }
      } else {
        // have we interrupted the sequence, stash last 'Out' if we have one
        if ($prev) {
            $result[$prev] = $out[$prev];
            $inSequence = !$inSequence; // toggle out of a sequence
        }
        // add current data that does not start with 'Out'
        $result[$year] = $data;
      }
      // Remember current item in case we need it next time round, or to add it on the end.
      $prev = $year;
    }
    
    // You'll need to do some checking to see if you actually need to add this on the end, but for the example data we do.
    $result[$prev] = $out[$prev];
    
    print_r($result);
    

    What this code does is to maintain a status of when we enter a sequence of "Out" values, and keeps track of the "last" item we looked at in case we need to insert it into the $result array because the current element is not an "Out".

    The output of this code is:

    Array
    (
        [2011] => Array
            (
                [0] => Out
                [1] => arrv
            )
        [2015] => Array
            (
                [0] => Out
            )
        [2016] => Array
            (
                [0] => some
                [1] => none
                [2] => test
            )
        [2017] => Array
            (
                [0] => Out
            )
        [2023] => Array
            (
                [0] => Out
                [1] => did
            )
    )
    

    Let me know if you need anything clarified.

    When I ran your code I see this output with error messages:

    year = 2011, data = Array
    (
        [0] => Out
        [1] => arrv
    )
    
    year = 2012, data = Array
    (
        [0] => Out
    )
    
    2012 contains the string; index is 1
    
       WARNING  Undefined array key 0 in phar:///Applications/Tinkerwell.app/Contents/Resources/tinkerwell/tinker.phar/src/Shell/CustomExecutionLoopClosure.php(38) : eval()'d code on line 20.
    
       WARNING  Trying to access array offset on null in phar:///Applications/Tinkerwell.app/Contents/Resources/tinkerwell/tinker.phar/src/Shell/CustomExecutionLoopClosure.php(38) : eval()'d code on line 20.
    
       DEPRECATED  str_contains(): Passing null to parameter #1 ($haystack) of type string is deprecated 
    
    ... etc
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search