From a performance standpoint, you need to visit every item in that list and there's no algorithm to apply that would get around that fact.
At best an alternative would perform the same as the nested loops.
From a flexibility standpoint, you have locked this code to deal with exactly this structure. In order to add another level or change one of the dicts to a list or vice-versa you have to finagle the code.
If you want code to accomodate objects of arbitrary depth you need recursion, and you can add logic to handle list/dict cases.
From a memory usage standpoint, you are using the maximum amount of memory for this task by constructing the entire output array all at once. The higher the number of items and/or the deeper the depth of the structure, the more memory it will require. This will grow exponentially-ish.
More often than not these arrays are generated once, iterated sequentially, and never touched again. Which is a perfect use case for a Generator. TLDR: A Generator is an iterable type that produces one element at a time, so you only have to hold one bit in memory at a time.
Taken together, we get something like:
function expand_array($input, $skip_list_keys=true) {
$is_list = array_is_list($input);
foreach($input as $key => $value) {
if( is_array($value) ) {
foreach( expand_array($value, $skip_list_keys) as $item ) {
if( $is_list && $skip_list_keys ) {
yield [ $value ];
} else {
yield array_merge([$key], $item);
}
}
} else {
if( $is_list && $skip_list_keys ) {
yield [ $value ];
} else {
yield [ $key, $value ];
}
}
}
}
foreach( expand_array($data) as $item ) {
printf("%s\n", json_encode($item));
}
echo PHP_EOL;
foreach( expand_array($data, false) as $item ) {
printf("%s\n", json_encode($item));
}
Output:
["category","sector","Sample A"]
["category","sector","Sample B"]
["category","sector","Sample C"]
["area","location","Location A"]
["area","location","Location B"]
["area","location","Location C"]
["category","sector",0,"Sample A"]
["category","sector",1,"Sample B"]
["category","sector",2,"Sample C"]
["area","location",0,"Location A"]
["area","location",1,"Location B"]
["area","location",2,"Location C"]