phparraysreplaceforeachdata-manipulation

Replace placeholder elements in a flat array with neighboring non-default values


I have an array that I want to loop through and make its elements copies of the previous element's value if it's equal to 'x'.

array [
    17 => "x",
    16 => "x",
    15 => "x",
    14 => "108.7000",
    13 => "x",
    12 => "x",
    11 => "x",
    10 => "x",
    09 => "108.2635",
    08 => "x",
    07 => "x",
    06 => "x",
    05 => "x",
    04 => "x",
    03 => "x",
    02 => "x",
    01 => "x",
    00 => "x",
    23 => "x",
    22 => "x",
    21 => "x",
    20 => "x",
    19 => "x",
    18 => "x"
]

For example, the output should be:

array [
    17 => "108.7000",
    16 => "108.7000",
    15 => "108.7000",
    14 => "108.7000",
    13 => "108.2635",
    12 => "108.2635",
    11 => "108.2635",
    10 => "108.2635",
    09 => "108.2635",
    08 => "108.2635",
    07 => "108.2635",
    06 => "108.2635",
    05 => "108.2635",
    04 => "108.2635",
    03 => "108.2635",
    02 => "108.2635",
    01 => "108.2635",
    00 => "108.2635",
    23 => "108.2635",
    22 => "108.2635",
    21 => "108.2635",
    20 => "108.2635",
    19 => "108.2635",
    18 => "108.2635"
]

As you can see keys above 14 became 108.7000, the letter 'x' will always be there, that is how I want to check.

I can't get my head around this. Maybe I even haven't used the right wording to describe the question.

Look at the key, 09: it has a value of 108.2635; below that are all 'x', which means they all should copy the 09 value and, above 09 until 04 are also 'x' values, which means they also should be 108.2635. Key 14 has its own value and above it are again 'x' values, which means they should copy the 14 value.


Solution

  • Try this-

    $data = [ '17' => "x", '16' => "x", '15' => "x", '14' => "x", '13' => "108.7000", '12' => "x", '11' => "x", '10' => "x", '09' => "x", '08' => "x", '07' => "x", '06' => "x", '05' => "x", '04' => "x", '03' => "x", '02' => "x", '01' => "x", '00' => "x", '23' => "x", '22' => "x", '21' => "x", '20' => "x", '19' => "x", '18' => "108.2635"];
    
    // Initially set reference as null. i.e. no reference value
    $reference = null;
    $group = [];
    
    // Reverse the order so that we can traverse from bottom to up
    $data = array_reverse($data, true);
    
    // Traverse the array
    foreach ($data as $key => $value)
    {
        /**
         * If there is no reference by which we exchange the 'x' value
         * then assign keys at an undefined group.
         */
        if ($reference === null && $value === 'x')
        {
            $group['undefined'][] = $key;
        }
        elseif ($reference === null && $value !== 'x')
        {
            /**
             * If reference not yet set but value is not 'x'
             * then set the reference as the non-x value which we find just now.
             * And change the 'undefined' group by newly found non-x value
             */
            $reference = $value;
    
            if (!empty($group['undefined']))
            {
                $group[$reference] = $group['undefined'];
                unset($group['undefined']);
            }
        }
        elseif ($reference !== null && $value === 'x')
        {
            /**
             * If reference is set and value is 'x'
             * then push into the key into reference group.
             */
            $group[$reference][] = $key;
        }
        elseif ($reference !== null && $value !== 'x')
        {
            /**
             * If reference is not null and value is also not 'x'
             * then change the reference by newly found non-x value
             * and make a new group and push the key into the group
             */
            $reference = $value;
            $group[$reference][] = $key;
        }
    }
    
    /**
     * Traverse the group and exchange the 'x' values
     * from the group reference.
     */
    foreach ($group as $value => $refs)
    {
        foreach ($refs as $key)
        {
            $data[$key] = $value;
        }
    }
    
    /**
     * Finally get the original order of the data array
     *
     */
    $data = array_reverse($data, true);
    
    print_r($data);