skip to Main Content

I have an input array like this

$input = [
    ["relation" => "OR"],
    ["color" => 'green'],
    ["color" => 'yellow'],
    ["relation" => "AND"],
    ["color" => 'black'],
    ["color" => 'orange'],
    ["relation" => "OR"],
    ["color" => 'blue'],
    ["color" => 'violet'],
];

Desired result:

$output = array(
    'relation' => 'OR',
    array(
        "color" => 'green'
    ),
    array(
        "color" => 'yellow'
    ),
    array(
        "relation" => "AND",
        array(
            "color" => "black"
        ),
        array(
            "color" => "orange"
        ),
        array(
            "relation" => "OR",
            array(
                "color" => "blue"
            ),
            array(
                "color" => "violet"
            ),
        )
    )
);

I believe I need to do make recursive function to handle this.

I have this but only works for a single level

function generate_nested_array($array, $nested_tax_query = array(), $target_index = 0)
{

    //the first element is always the relation
    $nested_tax_query['relation'] = $array[0]['relation'];
    // unset the first element as it is not needed anymore
    unset($array[0]);


    $len = count($array);
    // reindex the array
    $array = array_values($array);


    foreach ($array as $element_key => $element) {
        if (isset($element['relation'])) {
            $target_index = $element_key;
            break;
        }
    }


    // put everything below the target index into the target index and leave the rest as it is
    for ($i = 0; $i < $len - 1; $i++) {
        if ($i < $target_index) {
            $nested_tax_query[] = $array[$i];
        } else {
            $nested_tax_query[$target_index][] = $array[$i];
        }
    }

    // last item in the nested array
    $len_nested  = count($nested_tax_query);

    // last item in the in the nested array
    $last_item_in_nested_array  = $nested_tax_query[$len_nested - 2]; 


    return $nested_tax_query;
}

Is my approach correct?

2

Answers


  1. You’re right that recursion would be a good approach. First of all I would suggest preserving the original array as-is, so that you don’t have to think about the various modifications it will go through as you process it. To mark parts of it as already processed, you can use an index (as suggested by your target_index argument) or pass slices of the array to the recursive calls.

    I think you are close, you just need to do something with the rest of the array (if there are more elements to process) at the end of the function.

    Login or Signup to reply.
  2. I did not see the point in using recursion. I found reference variables to be a more intuitive approach. Every time you encounter a new relation, change the "reference" to be the new/last element where the reference was.

    When not dealing with relation data, you can safely push data directly into the current reference variable and it will be exactly where you wish it to be.

    Code: (Demo)

    $ref = [];
    $result = &$ref;
    foreach ($input as $row) {
        if  (key($row) !== 'relation') { // populate current level
            $ref[] = $row; // push color into reference
            continue;
        }
        if ($ref) {  // not the first relation encountered
            $ref = &$ref[];  // set $ref to point to new deeper subarray
        }
        $ref = $row; // push relation
    }
    
    var_export($result);
    

    Or with the same logic in a different orientation: (Demo)

    $ref = [];
    $result = &$ref;
    foreach ($input as $row) {
        if (key($row) === 'relation') {
            if ($ref) {  // not the first relation encountered
                $ref = &$ref[];  // set $ref to point to new deeper subarray
            }
            $ref = $row; // push relation
        } else {
            $ref[] = $row; // push color into reference
        }
    }
    
    var_export($result);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search