re-index array and add totals - php

I'm trying to figure out how to restructure an array and total values by given keys. I currently have an array called $data that is returning this result:
Bill => array:3 [▼
"01" => array:6 [▼
"Food " => array:2 [▶]
hamburger=>array:[
sales=> 210.00
purchases=>200.00
]
burrito=>array:[
sales=> 100.00
purchases=>40.00
]
"Drink " => array:2 [▶]
coke=>array:[
sales=> 210.00
purchases=>200.00
]
pepsi=>array:[
sales=> 100.00
purchases=>40.00
]
"total" => array:7 [▶]
sales=>620.00
purchases=>480.00
]
]
Ted => array:3 [▼
"01" => array:6 [▼
"Food " => array:2 [▶]
hamburger=>array:[
sales=> 110.00
purchases=>100.00
]
burrito=>array:[
sales=> 120.00
purchases=>40.00
]
"Drink " => array:2 [▶]
coke=>array:[
sales=> 110.00
purchases=>100.00
]
pepsi=>array:[
sales=> 120.00
purchases=>40.00
]
"total" => array:7 [▶]
sales=>460.00
purchases=>280.00
]
]
My issue is that I need to fit this into a laravel blade that is not concerned with bill or ted, but rather totals for everyone. Where the existing keys are "Bill" and "Ted", I would need the new structure to actually be identified by the "01", but I want to total all of the categories within that level. So I would be hoping to get results like this:
"01" =>[▼
"Food " => array:2 [▶]
hamburger=>array:[
sales=> 320.00
purchases=>300.00
]
burrito=>array:[
sales=> 220.00
purchases=>140.00
]
"Drink " => array:2 [▶]
coke=>array:[
sales=> 320.00
purchases=>300.00
]
pepsi=>array:[
sales=> 220.00
purchases=>80.00
]
"total" => array:7 [▶]
sales=>1080.00
purchases=>760.00
]
I can easily loop on this like:
foreach($data as $key=> $value){
foreach($value as $categoryNumber => $categories){
foreach($categories as $categoryDetails => $details){
}
}
}
But I'm completely stuck as to how to re-structure this and total by the new indices

I am not sure how you arrived at the above dd();, I am sure there is a better way of collecting these totals prior to arriving here. But now that you are here (say, you received this via an API or whatever), this would make the totals as you mentioned:
$result = [];
foreach ($input as $i) {
foreach ($i as $group => $n) {
if (!array_key_exists($group, $result)) $result[$group] = [];
foreach ($n as $category_name => $category) {
if (!array_key_exists($category_name, $result[$group])) $result[$group][$category_name] = [];
foreach ($category as $item_name => $item) {
if (!array_key_exists($item_name, $result[$group][$category_name])) {
$result[$group][$category_name][$item_name] = $item;
} else {
foreach ($item as $purpose => $dollars) {
$result[$group][$category_name][$item_name][$purpose] += $dollars;
}
}
}
}
}
}
In each step, I am checking if the array key exists, and if not, creating it. If you ignore those array_key_exists() checks, you'll see that I am simply copying the contents over and summing where necessary.

You do something like this...
<?php
$data = [
'Bill' => [
"01" => [
"Food" => [
'hamburger' => [
'sales' => 210.00,
'purchases' => 200.00,
],
'burrito' => [
'sales' => 100.00,
'purchases' => 40.00,
],
],
"Drink" => [
'coke' => [
'sales' => 210.00,
'purchases' => 200.00,
],
'pepsi' => [
'sales' => 100.00,
'purchases' => 40.00,
],
],
"total" => [
'sales' => 620.00,
'purchases' => 480.00,
],
]
],
'Ted' => [
"01" => [
"Food" => [
'hamburger' => [
'sales' => 110.00,
'purchases' => 100.00,
],
'burrito' => [
'sales' => 120.00,
'purchases' => 40.00,
],
],
"Drink" => [
'coke' => [
'sales' => 110.00,
'purchases' => 100.00,
],
'pepsi' => [
'sales' => 120.00,
'purchases' => 40.00,
],
],
"total" => [
'sales' => 460.00,
'purchases' => 280.00,
],
]
]
];
$finalResults = [];
foreach ($data as $userName => $bills) {
foreach ($bills as $billIndex => $billParts) {
if (!array_key_exists($billIndex, $finalResults)) {
$finalResults[$billIndex] = [
'total' => [
'sales' => 0,
'purchases' => 0,
]
];
}
foreach ($billParts as $partIndex => $details) {
if (!array_key_exists($partIndex, $finalResults[$billIndex])) {
$finalResults[$billIndex][$partIndex] = [];
}
if ($partIndex !== 'total') {
foreach ($details as $productCode => $productData) {
if (!array_key_exists($productCode, $finalResults[$billIndex][$partIndex])) {
$finalResults[$billIndex][$partIndex][$productCode] = [
'sales' => 0,
'purchases' => 0,
];
}
$finalResults[$billIndex][$partIndex][$productCode]['sales'] += $productData['sales'];
$finalResults[$billIndex][$partIndex][$productCode]['purchases'] += $productData['purchases'];
}
} else {
$finalResults[$billIndex][$partIndex]['sales'] += $details['sales'];
$finalResults[$billIndex][$partIndex]['purchases'] += $details['purchases'];
}
}
}
}
print_r($finalResults);

Related

PHP - Add new object to every array of objects

Consider this array of objects in PHP:
array:2 [
0 => array:4 [
"Row_Id" => 256
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "452"
]
1 => array:4 [
"Row_Id" => 257
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "42"
]
2 => array:4 [
"Row_Id" => 258
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "428"
]
]
I want to add "callee_number:100" in every array so my output should look like these:
array:2 [
0 => array:5 [
"Row_Id" => 256
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "452"
"callee_number" => "100"
]
1 => array:5 [
"Row_Id" => 257
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "42"
"callee_number" => "100"
]
2 => array:5 [
"Row_Id" => 258
"Start_Date" => "2020-05-16"
"account_code" => ""
"caller_number" => "428"
"callee_number" => "100"
]
]
I have taken the above input array in $get variable. Now I am calling array_push to append callee_number to every array:
array_push($get,[
'callee_number':'100'
]);
Also tried using array_merge but callee_number is not getting appended. How can I achieve that ?
Given the following array:
$array = [
[
"Row_Id" => 256,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "452",
],
[
"Row_Id" => 257,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "42",
],
[
"Row_Id" => 258,
"Start_Date" => "2020-05-16",
"account_code" => "",
"caller_number" => "428",
],
];
Native PHP
$array = array_map(function ($item) { return $item + ['callee_number' => 100]; }, $array);
Using collections
$array = collect($array)->map(function ($item) { return $item + ['callee_number' => 100]; })->toArray();
Using PHP 7.4 shorthands
$array = array_map(fn($item) => $item + ['callee_number' => 100], $array);
// Or
$array = collect($array)->map(fn($item) => $item + ['callee_number' => 100])->toArray();
To add or modify an element in each sub-array you would do this:
foreach ($get as &$g) {
$g["callee_number"] = 100;
}
Or this:
for ($c = 0; $c < count($get); $c++) {
$get[$c]["callee_number"] = 100;
}

Removed array grouped key

Is it possible to remove the key after data is grouped? Now I'm working with the csv file import function. I have two rows of data with the same student but different books because I want to group the books based on the student ID.
Code
foreach ($book as $item) {
$item['books'] = [
'number' => $item['number'],
'description' => $item['description'],
];
if (!isset($group_by[$item['student_id']])) {
$group_by[$item['student_id']] = array(
'student_id' => $item['student_id'],
'name' => $item['name'],
);
}
$group_by[$item['student_id']]['books'][] = $item['books'];
}
This is my grouping function, it worked perfectly as expected but the data structure is not matched to my system
Result is here
array:1 [
"ST001" => array:9 [
"student_id" => "ST001"
"name" => "joe"
"books" => array:2 [
0 => array:2 [
"number" => "1"
"description" => "The magic"
]
1 => array:2 [
"number" => "2"
"description" => "Forest in norway"
]
]
]
]
Expect result
array:9 [
"student_id" => "ST001"
"name" => "joe"
"books" => array:2 [
0 => array:2 [
"number" => "1"
"description" => "The magic"
]
1 => array:2 [
"number" => "2"
"description" => "Forest in norway"
]
]
]
I have no idea how to remove the St001 array. I did tried this $group_by[] = array( but the books data will be break out of data structure.
Assign the inner array to another array.
$array = $array['ST001'];
It will help out here
foreach($book as $item)
{
$item['books'] = ['number' => $item['number'], 'description' => $item['description'], ];
if (!isset($group_by[$item['student_id']]))
{
$group_by[$item['student_id']] = array(
'student_id' => $item['student_id'],
'name' => $item['name'],
);
}
$group_by[$item['student_id']]['books'][] = $item['books'];
}
// remove key and get only value as you want
print_r(array_values($group_by));

php how to grouping by id

I'm very new in PHP. I'm doing with the array data structure. Currently, I got two result which is the same ID but different details. I need to combine the details based on the ID.
This is my array result
array:2 [
0 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:1 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
]
]
1 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:1 [
0 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
]
This is my expected result
array:1 [
0 => array:13 [
"id" => "1"
"date" => "01-02-2019"
"order" => array:2 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
1 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
]
I'm trying to insert the order array if there have the same id
This is my code
public function order($value)
{
$group_id = [];
$groupItem = [];
foreach ($value as $item) {
$item['date'] = date('Y-m-d',strtotime($item['date']));
$groupItem = $item['order'][] = [
'id' => $item['id'],
'name' => $item['name'],
];
$group_id[$item['id']][]= $groupItem;
}
}
Result
array:1 [
"1" => array:1 [
0 => array:2 [
"code" => "F001"
"name" => "fish"
]
1 => array:2 [
"code" => "F002"
"name" => "chicken"
]
]
]
As you can see, I grouped the order but the date and id were missing.
Here is a working order function:
function order($input) {
$output = array();
foreach($input as $item) {
if (!isset($output[$item['id']])) {
$output[$item['id']] = array(
"id" => $item["id"],
"date" => $item["date"],
"order" => array()
);
}
$output[$item['id']]['order'][] = $item['order'];
}
return array_values($output);
}
INPUT:
array(
array(
"id" => "1",
"date" => "01-02-2019",
"order" => array(
array(
"code" => "F001",
"name" => "fish"
)
)
),
array(
"id" => "1",
"date" => "01-02-2019",
"order" => array(
array(
"code" => "F002",
"name" => "chicken"
)
)
)
);
OUTPUT:
array(
array(
"id"=> "1",
"date"=> "01-02-2019",
"order"=> array(
array(
array(
"code"=> "F001",
"name"=> "fish"
)
),
array(
array(
"code"=> "F002",
"name"=> "chicken"
)
)
)
)
)
Assign the proper data. Try -
foreach ($value as $item) {
$date = date('Y-m-d',strtotime($item['date']));
$id = $item['id'];
$group_id[$id]['id'] = $id;
$group_id[$id]['date'] = $date;
$group_id[$id]['order'][] = [
'id' => $item['id'],
'name' => $item['name'],
];
}
I would write something like this, if you need to account for multiple IDs:
$result = array_reduce( $input, function ( $result, $item ) {
$id = $item['id'];
if ( ! isset( $result[ $id ] ) ) { // We don't have an item yet.
$result[ $id ] = $item;
} else { // We have an item and need to add orders to it.
$result[ $id ]['order'] = array_merge( $result[ $id ]['order'], $item['order'] );
}
return $result;
}, [] );

Check if all of the values of a multidimensionnal array is null

I've a multidimensionnal array like that, and I wan't to check if all of the "open_at" and "closed_at" values are NULL.
array:7 [▼
0 => array:2 [▼
0 => array:2 [▼
"open_at" => null
"closed_at" => "11:03"
]
1 => array:2 [▼
"open_at" => "13:00"
"closed_at" => "16:00"
]
]
1 => array:2 [▼
0 => array:2 [▼
"open_at" => "09:00"
"closed_at" => "12:00"
]
1 => array:2 [▼
"open_at" => "12:30"
"closed_at" => "17:00"
]
]
2 => array:2 [▼
0 => array:2 [▼
"open_at" => "08:00"
"closed_at" => "18:00"
]
1 => array:2 [▼
"open_at" => null
"closed_at" => null
]
]
3 => array:2 [▼
0 => array:2 [▼
"open_at" => null
"closed_at" => null
]
1 => array:2 [▼
"open_at" => null
"closed_at" => null
]
]
...
I've tried with multiple for and foreach loop like, with no success...
for ( $i = 0; $i <6 ; $i++) {
for ($j = 0; $j < 2; $j++) {
if(empty($hours[$i][$j]["open_at"])){
$null="complete";
}
else{
$null="empty";
}
return $null;
}
}
The array should be checked as empty only if all the "open_at" and "closed_at" values are set to NULL.
As saw in the example above, the first values can be set to NULL, but the array should not be checked as empty in that case.
The goal is to don't execute the code bellow only if all the "open_at" and "closed_at" are set to NULL.
$hours = $request->get('hours');
//check if empty here
foreach ($hours as $key => $period) {
foreach($period as $attribute => $value){
$shops_hour = new Shops_hour();
$shops_hour->shop_id=$shop->id;
$shops_hour->day=$key;
$shops_hour->period=$attribute;
$shops_hour->open_at=$hours[$key][$attribute]["open_at"];
$shops_hour->closed_at=$hours[$key][$attribute]["closed_at"];
$shops_hour->save();
}
}
Thank you in advance,
Using a recursive function that will return true if all values contained are null:
function all_null_recursive($arr)
{
foreach ($arr as $item) {
/* if the item is an array
and the function itself found something different from null */
if (is_array($item) && all_null_recursive($item) === false) {
return false;
// if the item is not an array and different from null
} elseif (!is_array($item) && $item !== null) {
return false;
}
}
// always found null, everything's good
return true;
}
Testing:
The 2 arrays to test with.
$foo = [
0 => [
0 => [
"open_at" => null,
"closed_at" => "11:03"
],
1 => [
"open_at" => "13:00",
"closed_at" => "16:00"
],
],
1 => [
0 => [
"open_at" => "09:00",
"closed_at" => "12:00"
],
1 => [
"open_at" => "12:30",
"closed_at" => "17:00"
],
],
2 => [
0 => [
"open_at" => "08:00",
"closed_at" => "18:00"
],
1 => [
"open_at" => null,
"closed_at" => null
],
],
3 => [
0 => [
"open_at" => null,
"closed_at" => null
],
1 => [
"open_at" => null,
"closed_at" => null
]
]
];
$foo_2 = [
0 => [
0 => [
"open_at" => null,
"closed_at" => null
],
1 => [
"open_at" => null,
"closed_at" => null
],
],
1 => [
0 => [
"open_at" => null,
"closed_at" => null
],
1 => [
"open_at" => null,
"closed_at" => null
],
],
2 => [
0 => [
"open_at" => null,
"closed_at" => null
],
1 => [
"open_at" => null,
"closed_at" => null
],
],
3 => [
0 => [
"open_at" => null,
"closed_at" => null
],
1 => [
"open_at" => null,
"closed_at" => null
]
]
];
Testing:
var_dump(all_null_recursive($foo)); // bool(false)
var_dump(all_null_recursive($foo_2)); // bool(true)
The #jeff method work, thank you
$foundOneWithaValue = "0";
foreach ($hours as $key => $period) {
foreach($period as $attribute => $value){
if(!empty($hours[$key][$attribute]["open_at"]) || (!empty($hours[$key][$attribute]["closed_at"])) ) {
$foundOneWithaValue ++;
}
}
}
if($foundOneWithaValue != 0)
{
foreach ($hours as $key => $period) {
foreach($period as $attribute => $value){
$shops_hour = new Shops_hour();
$shops_hour->shop_id=$shop->id;
$shops_hour->day=$key;
$shops_hour->period=$attribute;
$shops_hour->open_at=$hours[$key][$attribute]["open_at"];
$shops_hour->closed_at=$hours[$key][$attribute]["closed_at"];
$shops_hour->save();
}
}
}

Transform laravel collection

I need a certain array format like this:
$data = [
1 => ['order' => 3],
2 => ['order' => 2],
3 => ['order' => 1]
];
So when I do:
$ids = $items->transform(function ($item) {
return [$item->id => ['order' => rand(1,10)]];
})->all();
Gives:
array:3 [
0 => array:1 [
1 => array:1 [
"order" => 8
]
]
1 => array:1 [
2 => array:1 [
"order" => 3
]
]
2 => array:1 [
3 => array:1 [
"order" => 10
]
]
]
How can I transform the array in a specific way I need above? TIA
you can use mapWithKeys, docs is here: https://laravel.com/docs/5.5/collections#method-mapwithkeys
$keyed = $items->mapWithKeys(function ($item) {
return [$item->id => ['order' => rand(1,10)]];
});
$ids = $keyed->all();

Categories