How to keep nested arrays on Laravel collection merge - php

I'm going crazy with that.
Given I have 2 arrays like
$array1 = [
"data_to_merge" => ["2020-03-11 16:00:00", "2020-03-24 14:00:00"],
"data_to_merge_past_year" => ["2019-03-11 16:00:00"],
];
$array2 = [
"data_to_merge" => [],
"data_to_merge_past_year" => ["2018-03-11 14:00:00"],
];
My goal is to have result like
all: [
"data_to_merge" => [
"2020-03-11 16:00:00",
"2020-03-24 14:00:00"
],
"data_to_merge_past_year" => [
"2018-03-11 14:00:00",
"2018-03-11 16:00:00",
],
],
I tried simple with
$result = collect($array1)->merge(collect($array2));
But with that approach it will remove the values from data_to_merge from my first array. Is there any Laravel way to get that result? It can be more than 2 arrays, just to demonstrate.
Here is my full example, it's basically the same
$array1 = [
"host" => "blablubb",
"data_to_merge" => [
"2020-03-11 16:00:00",
"2020-03-24 14:00:00"
],
"data_to_merge_past_year" => [
"2019-03-11 16:00:00"
],
];
$array2 = [
"host" => "blablubb",
"data_to_merge" => [],
"data_to_merge_past_year" => [
"2018-03-11 16:00:00"
],
];
$array3 = [
"host" => "blablubb",
"data_to_merge" => [],
"data_to_merge_past_year" => [],
];
$array4 = [
"host" => "blablubb",
"data_to_merge" => [
"2020-03-04 14:00:00",
"2020-03-04 17:00:00"
],
"data_to_merge_past_year" => [],
];
$all = collect([$array1, $array2, $array3, $array4]);
$all
->groupBy('host')
->map(function ($item) {
if (count($item) > 1) {
$result = collect([]);
foreach ($item as $subItem) {
$result = $result->merge($subItem);
}
return $result;
}
return $item->first();
})
->values()
->toArray();
Thanks guys!

You can use mergeRecursive for this:
$array1 = [
"data_to_merge" => ["2020-03-11 16:00:00", "2020-03-24 14:00:00"],
"data_to_merge_past_year" => ["2019-03-11 16:00:00"],
];
$array2 = [
"data_to_merge" => [],
"data_to_merge_past_year" => ["2018-03-11 14:00:00"],
];
$result = collect($array1)->mergeRecursive(collect($array2));
Result:
Illuminate\Support\Collection {#1278 ▼
#items: array:2 [▼
"data_to_merge" => array:2 [▼
0 => "2020-03-11 16:00:00"
1 => "2020-03-24 14:00:00"
]
"data_to_merge_past_year" => array:2 [▼
0 => "2019-03-11 16:00:00"
1 => "2018-03-11 14:00:00"
]
]
}
From the docs:
The mergeRecursive method merges the given array or collection
recursively with the original collection. If a string key in the given
items matches a string key in the original collection, then the values
for these keys are merged together into an array, and this is done
recursively:
$collection = collect(['product_id' => 1, 'price' => 100]);
$merged = $collection->mergeRecursive(['product_id' => 2, 'price' => 200, 'discount' => false]);
$merged->all();
// ['product_id' => [1, 2], 'price' => [100, 200], 'discount' => false]

Related

How to apply custom keys to my sequential array/collection of arrays using Laravel or PHP?

I'm trying to apply custom keys to a collection in laravel.
The best way that I found was using functions like transform or mapWithKeys.
$result = $collection->map(function ($item) {
return [
'custom_key_name_1' => $item[0],
'custom_key_name_2' => $item[1],
'custom_key_name_3' => $item[2],
];
});
I was hoping to find something like:
$keys = ['custom_key_name_1', 'custom_key_name_2', 'custom_key_name_3'];
result = $collection->withKeys($keys);
Do you know any other way to do that with a less verbose code?
I'm working in a legacy Laravel 5.5 project.
Input Example
$collection = collect([
[ 'first', 'second', 'third' ],
[ '1', '2', '3' ],
[ '1st', '2nd', '3rd' ],
]);
Expected Output
[
[
'custom_key_name_1' => 'first',
'custom_key_name_2' => 'second',
'custom_key_name_3' => 'third',
],
[
'custom_key_name_1' => '1',
'custom_key_name_2' => '2',
'custom_key_name_3' => '3',
],
[
'custom_key_name_1' => '1st',
'custom_key_name_2' => '2nd',
'custom_key_name_3' => '3rd',
],
]
Since you're working with a collection of arrays, you can use PHP's array_combine() method to put the keys and values together:
$collection = collect([
[ 'first', 'second', 'third' ],
[ '1', '2', '3' ],
[ '1st', '2nd', '3rd' ],
]);
$keys = ['custom_key_name_1', 'custom_key_name_2', 'custom_key_name_3'];
$result = $collection->map(fn ($v) => array_combine($keys, $v));
dump($result);
Result:
Illuminate\Support\Collection^ {#5189
#items: array:3 [
0 => array:3 [
"custom_key_name_1" => "first"
"custom_key_name_2" => "second"
"custom_key_name_3" => "third"
]
1 => array:3 [
"custom_key_name_1" => "1"
"custom_key_name_2" => "2"
"custom_key_name_3" => "3"
]
2 => array:3 [
"custom_key_name_1" => "1st"
"custom_key_name_2" => "2nd"
"custom_key_name_3" => "3rd"
]
]
#escapeWhenCastingToString: false
}
The important caveat being that, per the documentation, "a ValueError is thrown if the number of elements in keys and values does not match."

Create Multidimensional Tree Object From Array In PHP

I need to take an array that turns the key (split by /) of each element into a child array, and assigns the data in the right format in the new array.
There can be multiple levels of nesting, realistically never more then 10, but that is to be decided.
For example;
given the input of
$i_have_this = [
"Base/child" => [
[
"filename" => "child-1",
"last_modified" => "29/01/2020"
],
[
"filename" => "child-2",
"last_modified" => "29/01/2020"
],
[
"filename" => "child-3",
"last_modified" => "29/01/2020"
]
],
"Base/child/grandChild1" => [
[
"filename" => "grandChild1-1",
"last_modified" => "29/01/2020"
]
],
"Base/child/grandChild2" => [
[
"filename" => "grandChild2-1",
"last_modified" => "29/01/2020"
],
[
"filename" => "grandChild2-2",
"last_modified" => "29/01/2020"
],
[
"filename" => "grandChild2-3",
"last_modified" => "29/01/2020"
],
[
"filename" => "grandChild2-4",
"last_modified" => "29/01/2020"
],
[
"filename" => "grandChild2-5",
"last_modified" => "29/01/2020"
]
]
];
I would like the output of
$want_this = [
'name' => 'Base',
'children' => [
[
'name' => 'child',
'children' => [
["name" => "child-1"],
["name" => "child-2"],
["name" => "child-3"],
[
"name" => "grandChild1",
"children" => [
["name" => "grandChild1-1"]
]
],
[
"name" => "grandChild2",
"children" => [
["name" => "grandChild2-1"],
["name" => "grandChild2-2"],
["name" => "grandChild2-3"],
["name" => "grandChild2-4"]
]
],
]
]
]
];
So far I have;
foreach($i_have_this as $path => $value) {
$temp = &$want_this;
foreach (explode('/', $path) as $key) {
$temp = &$temp[$key];
}
$temp = $value;
}
but can't quite finish it off.
Example code run here
I think you could treat this the same way that most use "dot" notation for arrays (like in Laravel). Just replace "." with "/" in your case:
Example Code
function unflatten($data) {
$output = [];
foreach ($data as $key => $value) {
$parts = explode('/', $key);
$nested = &$output;
while (count($parts) > 1) {
$nested = &$nested[array_shift($parts)];
if (!is_array($nested)) $nested = [];
}
$nested[array_shift($parts)] = $value;
}
return $output;
}
print_r(unflatten($i_have_this));

How to fetch data from associative array in blade?

I am trying to fetch keys of array separately and values separately.
actual output:
[
"IT" => [
"Programming" => [
0 => "Python" 1 => "Java"
],
"Networking" => [
0 => "CCNA"
]
],
"Business" => [
"Power BI" => [
0 => "Power BI foundation"
]
]
]
desired output:
[
"IT",
"Business"
]
[
"Programming",
"Networking"
]
Does this script what you need?
$arr = [
"IT" => [
"Programming" => [
0 => "Python",
1 => "Java"
],
"Networking" => [
0 => "CCNA"
]
],
"Business" => [
"Power BI" => [
0 => "Power BI foundation"
]
]
];
$categories = [];
$subcategories = [];
foreach($arr as $key => $value) {
array_push($categories, $key);
array_push($subcategories, array_keys($value));
}
$categories equals:
["IT","Business"]
$subcategories equals :
[
["Programming","Networking"],
["Power BI"]
]
after execution.
Nevertheless, I would recommend to restructure your fetch script that has the array contained in $arr as output to avoid unnecessary loops.

Remove multidimensional array with empty sub arrays using PHP

I have this array as follows. Every student has 7 arrays starting from Monday to Sunday and inner array of each has events for day
$array = [
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
],
'christoper'=>[
[],[],[],[],[],[],[]
]
];
The output array should be
[
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
]
];
I have tried this
$array = array_filter(array_map('array_filter', $array));
but the result is vain. Can anyone help me in getting desired output. I want to filter out students with no events
You can do this:
<?php
$output = array_filter($array, function (array $studentDays) {
foreach ($studentDays as $day) {
// if there is a *non-empty* day, we return early and keep the whole record
if (! empty($day)) {
return true;
}
}
// only empty days, so discard the record
return false;
});
https://3v4l.org/AkshS
Loop over array and apply array_filter
$array = [
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
],
'christoper'=>[
[],[],[],[],[],[],[]
]
];
foreach( $array as $key => $value ){
$array[$key] = array_filter($value);
}
print_r( $array );
A recursive call to array_filter will do the job; in the outer call we check the size of the returned array to decide whether to keep that element or not (it will be 0 if the array consisted solely of empty arrays, as it does for 'christopher'):
$array = array_filter($array, function ($v) { return count(array_filter($v)); });
Demo on 3v4l.org

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