How I can in laravel map function continue loop?
I have code:
return collect($response->rows ?? [])->map(function (array $userRow) {
if ($userRow[0] == 'Returning Visitor') {
return [
$userRow[1] => [
'type' => $userRow[0],
'sessions' => (int) $userRow[2],
]
];
} else {
return false;
}
});
And output:
Collection {#986 ▼
#items: array:4 [▼
0 => false
1 => false
2 => array:1 [▶]
3 => array:1 [▶]
]
}
I don't need params with false, I need continue it or delete. How I can resolve this?
You can add a reject function after the map to remove all values that are false.
return collect($response->rows ?? [])
->map(function (array $userRow) {
if ($userRow[0] == 'Returning Visitor') {
return [
$userRow[1] => [
'type' => $userRow[0],
'sessions' => (int) $userRow[2],
]
];
} else {
return false;
}
})
->reject(function ($value) {
return $value === false;
});
You can use filter() or reject() (inverse of filter) to filter your collection, then map as you need. Something like this:
return collect($response->rows ?? [])->filter(function (array $userRow) {
return $userRow[0] == 'Returning Visitor';
})->map(function (array $userRow) {
return [
$userRow[1] => [
'type' => $userRow[0],
'sessions' => (int) $userRow[2],
]
];
});
Related
I want to convert all of my static data to collection in Laravel.
This is my data:
static $menu_list = [
[
'path' => 'admin/report/transaction',
'active' => 'admin/report',
'name' => 'Report',
'icon' => 'file-text',
'children' => [
'path' => 'admin/report/transaction',
'active' => 'admin/report/transaction',
'name' => 'Transaction',
],
],
];
This function converts my data to array:
public static function menuList()
{
$menu_list = collect(self::$menu_list)->map(function ($voucher) {
return (object) $voucher;
});
}
but function above can only convert main of array, it can't convert children => [...] to collection.
You need a recursive call.
public static function convertToCollection()
{
$menu_list = self::menuList(self::$menu_list);
}
public static function menuList($list)
{
return collect($list)->map(function ($voucher) {
if(is_array($voucher)) {
return self::menuList($voucher)
}
return $voucher;
});
}
You need to use collect() inside map() again:
public static function menuList()
{
$menu_list = collect(self::$menu_list)->map(function ($voucher) {
return (object) array_merge($voucher, [
'children' => collect($voucher['children'])
]);
});
}
Just add a small code peace to your approach.
$menu_list = collect(self::$menu_list)->map(function ($voucher) {
$voucher['children'] = (object) $voucher['children'];
return (object) $voucher;
});
Output
Illuminate\Support\Collection {#574 ▼
#items: array:1 [▼
0 => {#573 ▼
+"path": "admin/report/transaction"
+"active": "admin/report"
+"name": "Report"
+"icon": "file-text"
+"children": {#567 ▼
+"path": "admin/report/transaction"
+"active": "admin/report/transaction"
+"name": "Transaction"
}
}
]
}
I have an array in an array in an array. How can I search if any of these arrays have a specific key and value? If not remove this array from array.
Example:
array:3 [▼
0 => array:2 [▼
"location" => array:4 [▶]
"promotions" => array:1 [▶]
]
1 => array:2 [▼
"city" => array:4 [▶]
"promotions" => array:2 [▼
0 => array:5 [▶]
1 => array:5 [▼
"distance" => "0.2288511878121104"
"promoid" => 54
"promo" => Promotion {#1259 ▶}
"product" => Products {#1162 ▶}
"productID" => 5
]
]
]
2 => array:2 [▼
"city" => array:4 [▶]
"promotions" => []
]
]
I want to search "productID" with value 5, and I want to remove array in promotions which doesn`t have this value.
SOLVED
foreach ($locations as $key => $location) {
foreach ($location['promotions'] as $item => $promotions) {
if (is_array($promotions)) {
foreach ($promotions as $k => $value) {
if (!is_array($value)) {
if ($k == 'productID' && $value != $id) {
unset($locations[$key]['promotions'][$item]);
}
}
}
}
}
}
You could use a recursive function and unset() the target
<?php
// example code
$a = [
'test' => 'foo',
'bar' => [
'productID' => 5,
'something' => 'else'
],
'bar2' => [
'productID' => 6,
'something2' => 'else'
]
];
function removeItem($array, $search) {
$s = explode(":",$search);
$skey = trim($s[0]);
$sval = trim($s[1]);
foreach ($array as $n => $v) {
if ($n == $skey && $v == $sval) {
unset($array[$n]);
} else {
if (is_array($v)) $v = removeItem($v, $search);
$array[$n] = $v;
}
}
return $array;
}
$a = removeItem($a, 'productID:5');
print_r($a);
example: https://www.tehplayground.com/zJ2bKplP1pDaV8Ss
Nice solve, you can skip the 3er loop, checking if the key is set with isset()
foreach ($arr as $key => $location) {
if (!is_array($location)) { //if child is not an array ignore it
continue;
}
foreach ($location as $item => $promotions) {
if (!is_array($location)) {//if child is not an array ignore it
continue;
}
if (
isset($promotions['productID']) && //3er lvl, Has the key?
$promotions['productID'] == $id //Has the id
) {
continue; //This is a match so, ignore it
} else {
unset($arr[$key][$item]); //This promotion doesn't have it.
}
}
}
And this one checks at all levels, it uses recursive fn
$ans = deepClean($arr, 'productID', 5);
function deepClean($arr, $search_key, $search_value): ?array
{
if (
isset($arr[$search_key]) && //Has the key
$arr[$search_key] == $search_value //Match value
) {
return $arr;
}
//check children
$currentLevel = [];
foreach ($arr as $key => $value) {
if (!is_array($value)) {
continue;
}
$deepArr = deepClean($value, $search_key, $search_value);
if (is_array($deepArr)) { //child has search?
$currentLevel[$key] = $deepArr;
}
}
return $currentLevel === [] ? null : $currentLevel;
}
Hi I have reservations and their start times. Now I need to raport it.
$monthlyAmounts = Reservation::all()
->groupBy(function ($proj) {
return cdate($proj->start_time)->format('Y-m');
})
->map(function ($month) {
return $this->sumTime($month);
});
sumTime is my function to calculate diff between start time and end time.
cdate is helper -> carbon::parse($date)..
Result of this is:
array:2 [▼
"2020-01" => 60
"2020-02" => 420
]
Need
But for API it would be better to get like this:
[
"2020" => [
'01' => 60,
'02' => 30
],
"2021" => [
'01' => 30,
]
]
My try
Unfortunately I can't make it like that. I tried:
$monthlyAmounts = Reservation::all()
->groupBy(function ($proj) {
return cdate($proj->start_time)->format('Y-m');
})
->map(function ($month) {
return $this->sumTime($month);
})
->mapToGroups(function ($item,$key) {
$arrkey = explode('-',$key);
return [$arrkey[0]=>[$arrkey[1]=>$item]];
});
But It makes this:
array:1 [▼
2020 => array:2 [▼
0 => array:1 [▼
"01" => 60
]
1 => array:1 [▼
"02" => 420
]
]
]
So I can't do $res['2020']['01']. How to do It?
Try this:
$monthlyAmounts = Reservation::all()
->groupBy(function ($proj) {
return cdate($proj->start_time)->format('Y');
})
->map(function ($items) {
return $items->groupBy(function($item) {
return cdate($item->start_time)->format('m');
})
->map(function($month) {
return $this->sumTime($month);
});
});
Another method using foreach loop
...
$monthlyAmounts = Reservation::all();
$new = [];
foreach($monthlyAmounts as $key => $val)
{
$dis = explode('-', $key);
$new[$dis[0]][$dis[1] = $val;
}
print_r($new);
This question already has answers here:
How to Flatten a Multidimensional Array?
(31 answers)
Closed 3 years ago.
I have an eloquent object with data from the model which I need to convert to an array and have all indexes from the relations at the same array depth.
I tried array_flatten(), map(), filter() and other PHP methods but couldn't get it working correctly.
How I get my relations:
$data = Person::whereIn('id', $this->id[0])->where('school_id', '=',
$this->school)->with(['personinfo'=>function ($query) {
$query->select(
'person_id',
'general_info',
);
}, 'trades'=>function ($query) {
$query->select('person_id', 'trade_id')->with('trades');
}, 'measurements'=>function ($query) {
$query->select(
'person_id',
'measuring_point_1',
'measuring_point_1_date',
);
}])->get();
return $data->toArray();
What results in the array below, this is as close as I could get using different methods.
This is the outcome of the return function:
array:3 [
1 => array:17 [
"school_id" => 6
"birth_date" => null
"sex_id" => 1
"phone_number" => 62452676867897
"mobile_number" => 62398356786787
"email" => "example#example.com"
"personinfo" => array:5 [
"person_id" => 21
"general_info" => null
"health_info" => null
]
"trades" => array:3 [
"person_id" => 21
"trade_id" => 2
"trades" => array:8 [
"school_id" => 2
"name" => "blablabla"
]
]
"measurements" => array:7 [
"person_id" => 21
"measuring_point_1" => null
"measuring_point_1_date" => null
]
]
];
I need the array to be like this:
array:3 [
1 => array:17 [
"school_id" => 6
"birth_date" => null
"sex_id" => 1
"phone_number" => 624176676867897
"mobile_number" => 649498356786787
"email" => "example#example.com"
"person_id" => 21
"general_info" => null
"health_info" => null
"person_id" => 21
"trade_id" => 2
"school_id" => 2
"name" => "blablabla"
"person_id" => 21
"measuring_point_1" => null
"measuring_point_1_date" => null
]
]
];
Basically, I need to convert the multidimensional array to a zero depth array.
Any help would be appreciated.
You can use custom of array flatten with merging the inner with array-merge as:
function arrayFlatten($array) {
$res = array();
foreach ($array as $k => $v) {
if (is_array($v)) $return = array_merge($res, array_flatten($v)); // add recursively
else $res[$k] = $v; // just add
}
return $res;
}
Now just return arrayFlatten($data->toArray());
Simple live example
How i made it work using dWinder's answer
$data = Person::whereIn('id', $this->id[0])->where('school_id', '=', $this->school)->with(['personinfo'=>function ($query) {
$query->select(
'person_id',
'general_info',
);
}, 'trades'=>function ($query) {
$query->select('person_id', 'trade_id')->with('trades');
}, 'measurements'=>function ($query) {
$query->select(
'person_id',
'measuring_point_1',
'measuring_point_1_date',
);
}])->get();
function array_flatten($array)
{
$return = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$return = array_merge($return, array_flatten($value));
} else {
$return[$key] = $value;
}
}
return $return;
}
foreach ($data as $value) {
$result[] = array_flatten($value->toArray());
}
return $result;
I have a laravel collection on output, I want to parse it ->toArray()
Collection {#335
#items: array:2 [
"0f39b1e0-a507-11e7-9d6e-33e84951047e" => array:2 [
"total_amount" => 25000
"debt_type" => array:2 [
0 => "car_loan"
1 => "car_loan"
]
]
"0f218520-a507-11e7-b0ba-8554a4ad039b" => array:2 [
"total_amount" => 15000
"debt_type" => array:1 [
0 => "house_loan"
]
]
]
}
is there any way to parse it so I get the following output:
array:1[
0=>[
'debt_id'=>'0f39b1e0-a507-11e7-9d6e-33e84951047e',
'debt_type'=>'car_loan',
'total_amount'=>25000
],
1=>[
'debt_id'=>'0f218520-a507-11e7-b0ba-8554a4ad039b',
'debt_type'=>'house_loan',
'total_amount'=>15000
]
]
what I have tried it works but not sure if its a good way to go around it:
$appDebts = $appDebts->groupBy('debt_type_id')->map(function ($item) {
return [
'total_amount' => $item->sum('amount'),
'debt_type' => $item->map(function ($item) {
return $item->debt_type->slug;
})->toArray(),
];
})->toArray();
if you dd $appDebts you get the collection that I have added on top of the post
$carLoan = [];
$studentLoan = [];
$houseLoan = [];
$cardLoan = [];
foreach ($appDebts as $debt) {
if ($debt['debt_type'][0] === 'car_loan') {
$carLoan['TotalAmount'] = $debt['total_amount'];
$carLoan['LoanType'] = $debt['debt_type'][0];
}
if ($debt['debt_type'][0] === 'house_loan') {
$houseLoan['TotalAmount'] = $debt['total_amount'];
$houseLoan['LoanType'] = $debt['debt_type'][0];
}
if ($debt['debt_type'][0] === 'student_loan') {
$studentLoan['TotalAmount'] = $debt['total_amount'];
$studentLoan['LoanType'] = $debt['debt_type'][0];
}
if ($debt['debt_type'][0] === 'credit_card_loan') {
$cardLoan['TotalAmount'] = $debt['total_amount'];
$cardLoan['LoanType'] = $debt['debt_type'][0];
}
}
Based on the array you shared:
$parsed = $collection->map(function ($item, $id) {
return [
'debt_id' => $id,
'debt_type' => collect($item['debt_type'])->first(),
'total_amount' => $item['total_amount']
];
})->values()->toArray();
With values you remove the key => value, you get the array without keys
Try with this mapping after the first one that you did :
$appDebts = $appDebts->groupBy('debt_type_id')->map(function ($item) {
return [
'total_amount' => $item->sum('amount'),
'debt_type' => $item->map(function ($item) {
return $item->debt_type->slug;
})->toArray(),
];
}); // <-- remove ->toArray() from here
$appDebts = $appDebts->map(function ($item, $key) {
return [
'debt_type_id' => $key
'debt_type' => $item["debt_type"][0], // assuming you want the first type !!
'total_amount' => $item["total_amount"],
];
})->toArray();
PS : This convert the given collection to tha wanted array for more performance tweaking consider editing the SQL query or the logic of getting appDebts
The only thing I can add to #Llopele's answer is to use keyBy() for easier data access:
$parsed = $collection->map(function ($item, $id) {
return [
'debt_id' => $id,
'debt_type' => collect($item['debt_type'])->first(),
'total_amount' => $item['total_amount']
];
})->values()->keyBy('debt_type')->toArray();
So now you can access data like this Arr::get($parsed, 'house_loan');