Search code examples
phparraysmultidimensional-arraygrouping

Group integer values in a flat array by non-integer values to create a 3-level array


I'm trying to take data that is received from form input and, in PHP, change the way it is ordered for use in a template creation module/app. I need it to be in a multidimensional array for use.

How the array currently looks

$templateData = [
    0 => 'h',
    1 => 1,
    2 => 2,
    3 => 3,
    4 => 'c-1-3',
    5 => 3,
    6 => 5,
    7 => 'c-2-3',
    8 => 3,
    9 => 'c-3-3',
    10 => 'f',
    11 => 2
];

How the array should look

$templateData = [
    0 =>[ //header row
        0 => [1,2,3] //column
    ],
    1 =>[ //content row(s)
        0 => [3,5], //column
        1 => [3],
        2 => [0]
    ],
    2 => [ //footer row
        0 => [2] //column
    ]
]

The 'h' represents the start of the header row of the template and 'c-1-3' represents a the start of a row with 3 columns starting with the first column. The 'f' represents the start of the footer row. I'm just drawing a blank right now and I can't wrap my head around it.

Here is where I'm at right now, but it's still not working as intended:

$elements = $request->input('elements'); //laravel code that grabs array input
$row = 0;
$column = 0;
foreach($elements as $key => $element) {
    //if value is a letter
    if(preg_match('/^[a-zA-Z]/', $element)) {
        //if the 3rd letter in the string is a 1
        if(!isset($element[2]) || $element[2] == '1') { $row++; }
        //cycle through values after current key
        for($i=$key+1; $i < count($elements);$i++){
            //until you hit another letter
            if(preg_match('/^[a-zA-Z]/', $elements[$i])) { break; }
            $column++;
            $temp[$row][$column][] = $elements[$i];
        }
        $column = 0;
    }
}

The $templateData and $elements variables are the same in the the above and below context.


Solution

  • This is the code I ended up with. Finally got it. This works:

        //grab input
        $elements = $request->input('elements');
    
        //initiate row/column numbers
        $row = 0;
        $column = 0;
        $templateData = array();
    
        //loop through each array value
        foreach($elements as $key => $element) {
    
            //if value starts with a letter
            if(preg_match('/^[a-z]/', $element)){
    
                //set total columns
                if($element != 'h' && $element != 'f')
                {
                    $totalColumns = substr($element, 4);
                } else {
                    $column = 1;
                    $totalColumns = 1;
                }
    
                //if h, c-1-*, or f is detected advance the row
                if(substr($elements[$key], 0) == 'h' || substr($elements[$key], 2) == 1 || substr($elements[$key], 0) == 'f')
                {
                    $row++;
                }
    
                //loop through keys following first recognized letter until you hit another letter
                for($i = $key+1; $i < count($elements) && !preg_match('/^[a-z]/',$elements[$i]); $i++)
                {
                    //add element id to column
                    $templateData[$row-1][$column-1][] = $elements[$i];
                }
    
                //if first value in column is not set, add a 0 value to column
                if(!isset($templateData[$row-1][$column-1][0]))
                {
                    $templateData[$row-1][$column-1][0] = 0;
                }
    
                //if its the last column in the set, set to 0
                if($column == $totalColumns)
                {
                    $column = 0;
                }
    
                $column++;
            }
        }
        dd($templateData);