How to apply custom keys to my sequential array/collection of arrays using Laravel or PHP? - 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."

Related

How to keep nested arrays on Laravel collection merge

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]

PHP - Sort array by subarray value based on a second array

I've done some research including going through PHP Sort Array By SubArray Value but this is a variation:
I have an array as follows:
$data =
[
0 => [
'id' => (int) 5,
'name' => 'Foo',
'group_id' => (int) 1,
],
1 => [
'id' => (int) 6,
'name' => 'Bar',
'group_id' => (int) 1,
],
2 => [
'id' => (int) 8,
'name' => 'Baz',
'group_id' => (int) 7,
],
3 => [
'id' => (int) 9,
'name' => 'ABC',
'group_id' => (int) 2,
],
4 => [
'id' => (int) 10,
'name' => 'DEF',
'group_id' => (int) 65,
]
];
I also have an array second array of group_id's that are relevant to a search a user has performed:
$gids = [7, 65];
What I want to do is order $data by group_id based on the values inside $gids. So the order of $data should become:
0 => [
'id' => (int) 8,
'name' => 'Baz',
'group_id' => (int) 7,
],
1 => [
'id' => (int) 10,
'name' => 'DEF',
'group_id' => (int) 65,
]
2 => [
'id' => (int) 5,
'name' => 'Foo',
'group_id' => (int) 1,
],
3 => [
'id' => (int) 6,
'name' => 'Bar',
'group_id' => (int) 1,
],
4 => [
'id' => (int) 9,
'name' => 'ABC',
'group_id' => (int) 2,
],
Note that once the $gids array has been taken into account, the group_id of the remaining items in $data is numerical (ascending order in this case: 1, 1, 2).
I understand it's possible to use usort and an anonymous function, e.g.
usort($data, function ($gids) {
});
However, I don't understand what to write inside this function to perform ordering in this way? My initial thought was to do a foreach($gids) followed by a foreach($data) and compare the group_id value. But I don't know what to do in terms of modifying $data so that it reorders.
Please can someone help?
Equally, if there is already a post which explains how to do this please let me know, because I couldn't find one on here. The original link simply bases ordering numerically, not on a second array ($gids equivalent).
Using PHP 7.1.0
This should do the trick
usort($data, function($a, $b) use ($gids)
{
$posA = array_search($a['group_id'], $gids);
if ($posA === false) {
$posA = 9999;
}
$posB = array_search($b['group_id'], $gids);
if ($posB === false) {
$posB = 9999;
}
return $posA - $posB;
});
If found in the array of $gids, the sorting of $gids will be used, else the elements will stay in the order they're given in.
The return I'm getting is the following:
array:5 [▼ 0 => array:3 [▼
"id" => 8
"name" => "Baz"
"group_id" => 7 ] 1 => array:3 [▼
"id" => 10
"name" => "DEF"
"group_id" => 65 ] 2 => array:3 [▼
"id" => 5
"name" => "Foo"
"group_id" => 1 ] 3 => array:3 [▼
"id" => 6
"name" => "Bar"
"group_id" => 1 ] 4 => array:3 [▼
"id" => 9
"name" => "ABC"
"group_id" => 2 ] ]

Multidimensional Array Sorting/Chaining Based on Value PHP

I have an array below format:
$data = [
'2018-04-26' => [
[
'op' => 3,
'cl' => 4
],
[
'op' => 3,
'cl' => 2
],
[
'op' => 4,
'cl' => 3
]
]
];
I want to make it sort as
$data['2018-04-26'] = [
[
'op' => 3,
'cl' => 4
],
[
'op' => 4,
'cl' => 3
],
[
'op' => 3,
'cl' => 2
]
];
How will I sort based on OP, CL.
OP of current array is equal to previous array CL. or
CL of current array is equal to next array OP.
We can start any where but let start accordingly index 0-n.
There is no chance for multiple solution.
If same op/cl appeared we can put it anywhere.
I have tried using usort() but how do I put the logic.
function cmpare($a, $b){
//the logic
return 0;
}
usort($data['2018-04-26'], 'cmpare');
This is the php code:
$data = [];
$data['2018-04-26'][] = [
'op' => 3,
'cl' => 4
];
$data['2018-04-26'][] = [
'op' => 4,
'cl' => 3
];
$data['2018-04-26'][] = [
'op' => 3,
'cl' => 2
];
usort($data['2018-04-26'], function($a, $b){
return ($a['op'] == $b["cl"]) ? 1 : 0;
});

Merge indexed arrays from POST request

I have this array coming from post request:
$x = [
"meal" => [
"monday" => [
"breakfast" => [
0 => "type1",
1 => "type1",
],
"afternoonTea" => [
0 => "type2",
],
],
],
"number" => [
"monday" => [
"breakfast" => [
0 => "10",
1 => "9",
],
"afternoonTea" => [
0 => "1",
],
],
],
];
I am trying to merge all this into one array without using tones of foreaches.
Maybe someone more clever will know how to use iterators to achieve that.
Data from meal and number is always 1:1.
I need to convert this to something like this:
$x = [
"monday" => [
"breakfast" => [
[
'type' => "type1",
'number' => 10,
],
[
'type' => "type1",
'number' => 9
]
],
"afternoonTea" => [
[
'type' => "type2",
'number' => 1,
],
],
],
],
];
If you count 3 as being tonnes then this isn't your answer - but I can't see a way of reducing down the number of reach loops below this without getting to a game of code golf which won't be helpful.
Because you know there is a 1:1 relationship between meal and number, you can use the indexes from one to get data from the other by doing:
$result = [];
foreach($x['meal'] as $day => $list) {
foreach($list as $activity => $types) {
foreach($types as $i => $type) {
$result[$day][$activity][] = [
'type' => $type,
'value' => $x['number'][$day][$activity][$i],
];
}
}
}
The output of this will be $result will contain the array in the format you want.

Searching an array In Laravel

I been getting two arrays and merging them and then looking for a certain value under name but can't seem to get it working
$temp = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Abigail'],
];
$temp1 = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Taylor'],
];
$ggg = array_merge($temp,$temp1);
Use the contains() method of a collection. The schema:
collect($array1) // Create a collection from the first array
->merge($array2) // merge it with the second array
->contains($key, $value); // returns boolean
Your code:
$temp = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Abigail'],
];
$temp1 = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Taylor'],
];
collect($temp)->merge($temp1)->contains('name', 'Taylor'); // true
collect($temp)->merge($temp1)->contains('name', 'Jane'); // false
If you want to get the items who are matching the criteria, use where():
$result = collect($temp)->merge($temp1)->where('name', 'Taylor');
This will return:
Collection {#465 ▼
#items: array:3 [▼
0 => array:2 [▼
"id" => 3
"name" => "Taylor"
]
2 => array:2 [▼
"id" => 3
"name" => "Taylor"
]
3 => array:2 [▼
"id" => 3
"name" => "Taylor"
]
]
}
Use print_r($ggg) to print the resulting array. Referring to the name part you should use $ggg[0]['name'] for example. Not sure what is your final goal for merging the 2 arrays, do you want an array with all 4 elements ? The way you are doing it you will end up with only 2 elements, index 0 of $temp1 will overwrite index 0 of $temp, same thing with index 1.
I have tried and maybe this will help you.
$temp = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Abigail'],
];
$temp1 = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Taylor'],
];
$ggg = array_merge($temp,$temp1);
foreach ($ggg as $key) {
echo "ID: ".$key['id']."<br>";
echo "NAME: ".$key['name']."<br>";
}
I think you want something like below. Since you tagged this as Laravel I've done it with laravel specific code, but it would be possible to use native PHP too.
$temp = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Abigail'],
];
$temp1 = [
['id' => 3, 'name' => 'Taylor'],
['id' => 3, 'name' => 'Taylor'],
];
$item = collect($temp)->merge($temp1)->first(function ($item) {
return $item['name'] == 'Taylor';
});

Categories