I am trying to group data from a 2d array while leveraging a lookup array to ensure that default values exist in each group.
My lookup/mapping array associates language ids with language names.
$langs = [
5 => "english",
10 => "french",
12 => "german"
...
];
The other array holds the data which ahould be grouped by date value.
$posts = [
[
"date" => "13-07-2022",
"lang_id" => 5,
"amount" => 90,
],
[
"date" => "13-07-2022",
"lang_id" => 10,
"amount" => 34,
],
[
"date" => "14-07-2022",
"lang_id" => 5,
"amount" => 7,
],
...
];
Where the $posts
have the post in that language per day. When there weren't any posts, there won't be any entry in the array.
I want to restructure the data to be grouped by date and each subarray should contain the date and the accumulated, associative language amounts:
$result = [
[
"date" => "13-07-2022",
"english" => 90,
"french" => 34,
"german" => 0
],
[
"date" => "14-07-2022",
"english" => 6,
"french" => 0,
"german" => 0
],
...
];
This is, when there no posts from the "master" list of languages, I will set that language to 0.
I tried to iterate the $posts
and within it the langs
array in order to fill with zeros each new processed item, but I'm failing to fulfil it.
What I tried is:
$d = $post[0]['date'];
$result = [];
foreach ($posts as $post) {
if ($d != $post['date']) {
$d = $post['date'];
$result[] = $proc;
$proc = [];
$proc['date'] = $d;
}
foreach ($langs as $id => $name) {
if ($id == $post['lang_id']) {
$proc[$name] = $post['amount'];
} elseif (!isset($proc[$name])) {
$proc[$name] = 0;
}
}
}
$result[] = $proc;
My point is if there would be a better way to achieve this with no nested loop or more efficient way
If you loop through the posts array and for each item, first check if there is already a result for this date. If there isn't - it adds the values from langs in using array_fill_keys()
with a value of 0, and then adds the date in (you could make the date first by using array_merge()
).
Then it always adds in the various keys...
$results = [];
foreach ($posts as $post) {
if (array_key_exists($post['date'], $results) == false) {
$results[$post['date']] = array_fill_keys($langs, 0);
$results[$post['date']]['date'] = $post['date'];
}
$results[$post['date']][$langs[$post['lang_id']]] = $post['amount'];
}
var_dump(array_values($results));
which gives...
array(2) {
[0] =>
array(4) {
'english' =>
int(90)
'french' =>
int(34)
'german' =>
int(0)
'date' =>
string(10) "13-07-2022"
}
[1] =>
array(4) {
'english' =>
int(7)
'french' =>
int(0)
'german' =>
int(0)
'date' =>
string(10) "14-07-2022"
}
}
For putting the date first...
$results[$post['date']] = array_merge(['date' => $post['date']], array_fill_keys($langs, 0));