I need to group values in my flat array so that each non-integer value starts a new group/row in my result array and every integer value encountered until the next occurring non-integer should be pushed into a subarray in the respective group/row.
Input:
$unitsList = [
"Aulas Gratuitas",
"149",
"151",
"153",
"Módulo 0",
"964",
"989",
"Módulo 1",
"985",
"1079",
"1001",
"1003"
"Módulo 2",
"1009"
];
Current code:
$newArr = array();
foreach( $unitsList as $item ) {
if( !is_numeric($item) ) {
$title = array( "title" => $item, "units" => "" );
array_push( $newArr, $title);
} elseif ( is_numeric($item) ) {
$number = $item;
array_push( $newArr, $number);
}
}
Current result:
[
[
"title" => "Aulas Gratuitas",
"units" => ""
]
"149",
"151",
"153",
[
"title" => "Módulo 0",
"units" => ""
],
"964",
"989",
[
"title" => 'Módulo 1',
"units" => ""
],
"985",
"1079",
"1001",
"1003"
[
"title" => 'Módulo 2',
"units" => ''
],
"1009"
]
As you can see, I am having a hard time adding the numbers into the "units" key.
Desired result:
[
[
"title" => "Aulas Gratuitas",
"units" => ["149", "151", "153"]
],
[
"title" => 'Módulo 0',
"units" => ["964", "989"]
],
[
"title" => 'Módulo 1',
"units" => ["985", "1079", "1001", "1003"]
],
[
"title" => "Módulo 2",
"units" => ["1009"]
]
]
CodePudding user response:
$originalArray = ['a', 1, 2, 3, 'b', 4, 5, 6];
function formatArray($input) {
$output = [];
foreach($input as $inputRow) {
if (is_string($inputRow)) {
$output[] = ['title' => $inputRow, 'units' => []];
} else if (count($output)) {
$output[count($output)-1]['units'][] = $inputRow;
}
}
return $output;
}
var_dump(formatArray($originalArray));
Note that your numbers after the title CANNOT be strings, otherwise this function will recognize it as new titles.
This code will output:
array(2) {
[0]=>
array(2) {
["title"]=>
string(1) "a"
["units"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
}
[1]=>
array(2) {
["title"]=>
string(1) "b"
["units"]=>
array(3) {
[0]=>
int(4)
[1]=>
int(5)
[2]=>
int(6)
}
}
}
CodePudding user response:
Items in the given list aren't regular. The first item has three units, and the second has two units. We cannot convert them into the expected structure without controlling the type of each item. My solution is below. I added explanations as a comment line.
$values = array(
"string",
11111,
22222,
33333,
"string_2",
44444,
55555
);
$formattedArray = [];
$index = -1;
foreach ($values as $value) {
// If the value is a string, create the new array structure item and assign the title
if (is_string($value)) {
$index ;
$formattedArray[$index]['title'] = $value;
$formattedArray[$index]['units'] = [];
// The rest of the code in "foreach scope" is for integer values, so skip the remaining part
continue;
}
// If the following line is executing, the value is an integer
// Push the value to the current item's units
$formattedArray[$index]['units'][] = $value;
}
var_dump($formattedArray);
CodePudding user response:
So that you don't need to keep track of first level indexes, use a reference variable and push related data into that AFTER pushing the new row into the result array.
Code: (Demo)
$result = [];
foreach ($array as $value) {
if (!ctype_digit($value)) {
unset($units);
$units = [];
$result[] = ['title' => $value, 'units' => &$units];
} else {
$units[] = $value;
}
}
var_export($result);
unset()
is used to destroy the reference to the previous group, otherwise newly pushed data would be sent to two (or more) places in the result array.Reference variables have a default value of
null
. If yourtitle
values are guaranteed to be followed by an integer/unit value, then$units = [];
can be removed. If you have atitle
and then anothertitle
there will be no data for the formertitle
group. With the explicit array declaration, the group will have an emptyunits
array instead ofnull
.
Related questions answered with the same general technique: