I have below array, which includes a set of default indexes, that must be present in my final array:
'entities' => [
'deliveredAt',
'issuedAt',
'totals' => [
'due',
'gross',
'net',
'tax' => [
'amount',
'net',
'rate',
],
]
],
The above array is saved in a variable called $entities.
Now, I have a 3rd party API, that will return the above entities, but only include them in the response if the entity contains a value.
For example, a $response can look like this:
array:2 [▼
"issuedAt" => "2020-08-20"
"totals" => array:1 [▼
"tax" => []
]
]
As you can see, if comparing the returned array with the indexes that I expect, there is a few missing:
deliveredAt
totals.due, totals.gross, totals.net, totals.tax.amount, totals.tax.net, totals.tax.rate
I am trying to make a method that can iterate over the $response array, and check if it contains the indexes that I expect. If not, I simply want to set the index with a value of null.
Below is what I have so far:
foreach ($entities as $key => $entity) {
if (!is_array($entity)) {
if (!isset($response[$entity])) {
$response[$entity] = null;
}
}
}
However, this will only add an index that is not an array. In this example, it will only add: deliveredAt => null.
How can I do, so the above method can iterate through multiple at least 2 nested arrays and add the index name and null value?
You can define initial array with keys and NULL (or whatever you need) as values:
$entities = [
'deliveredAt' => null,
'issuedAt' => null,
'totals' => [
'due' => null,
'gross' => null,
'net' => null,
'tax' => [
'amount' => null,
'net' => null,
'rate' => null,
],
]
];
// here's your real data
$realData = [
"issuedAt" => "2020-08-20",
"totals" => [
"tax" => [
'net' => 42,
]
]
];
// now use array_replace_recursive to replace keys in `$entities` with values of `$realData`
print_r(array_replace_recursive($entities, $realData));
Fiddle.
Also note that keys from $realData that do not exist in $entities will be added to result.
You can use array_replace_recursive for doing this. You had only to change your associative array entities a little bit, so every property needs a initiliasation (e.g. NULL or '').
$result = array_replace_recursive($entities, $array);
Here you can test it http://sandbox.onlinephpfunctions.com/code/4688ed3240050479edeef7c9e4da16f98dbe01de
Here is the hole code:
$array = [
"issuedAt" => "2020-08-20",
"totals" => [
"tax" => [
'amount' => 100
]
]
];
$entities = [
'deliveredAt' => NULL,
'issuedAt' => NULL,
'totals' => [
'due' => NULL,
'gross' => NULL,
'net' => NULL,
'tax' => [
'amount' => NULL,
'net' => NULL,
'rate' => NULL
],
]
];
$result = array_replace_recursive($entities, $array);
var_dump($result);
Related
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."
There's a thing that I don't understand when I use array_merge() :
$defaultOptions = [
'active' => null,
'activeClass' => 'active',
'wrapper' => [
'attributes' => null,
'templateVars' => null
],
'item' => [
'hasChildrenClass' => '', // this disappears after array_merge
'attributes' => null,
'linkAttrs' => null,
'templateVars' => null
]
];
$options = [
'active' => [5,3],
'item' => [
'attributes' => ['class' => 'test']
]
];
$options = array_merge($defaultOptions, $options);
The result of $options is
[
'active' => [
(int) 0 => (int) 5,
(int) 1 => (int) 3,
],
'activeClass' => 'active',
'wrapper' => [
'attributes' => null,
'templateVars' => null,
],
'item' => [
'attributes' => [
'class' => 'test',
],
],
]
I don't understand why $options['item']['hasChildrenClass'] disappeared in my result ?
In array_merge() if the arrays have the same string keys, then values from the later arrays will overwrite the previous one. If the arrays have numeric keys, then values from the later arrays will appended with previous one. If the arrays contain null or empty values, this value will be skipped and removed from the merged array.
Read more at php.net manual
I have an array with 3 levels and I'd like to merge/flatten all 3rd level subarrays into one subarray/row on the 2nd level.
$array = [
[
'User' => [
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
[
'User' => [
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
],
[
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
],
];
The deep User-keyed subarrays (having 6 elements) should be merged with its sibling/indexed subarray (having 3 elements) to form a 9-element row on the second level.
Desired result:
[
[
'id' => 57341,
'updated' => null,
'userId' => 57341,
'value' => null,
'lat' => 53.4537812,
'lon' => -2.1792437,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
],
[
'id' => 57336,
'updated' => null,
'userId' => 57336,
'value' => null,
'lat' => 53.473684,
'lon' => -2.2399827,
'feed_likes' => 'NA',
'category_idx' => -1,
'type' => 'User'
]
]
You can use splat ... operator with array_merge
foreach($a as $child){
$flatten[] = array_merge(...$child);
}
Working example :- https://3v4l.org/HkUh6
To merge and flatten the 3rd level data sets into consolidated 2nd level rows with functional style programming, make iterated calls of array_merge() which receive all 3rd level payloads at once. The spread operator (...) is a concise technique used to unpack multiple elements in an array. A special consideration is needed for this case because spreading elements which have non-numeric keys will cause code breakage. To overcome this, simply call array_values() to "index" the array (replace all keys with sequenial numbers) before spreading.
Code: (Demo)
var_export(
array_map(
fn($rows) => array_merge(...array_values($rows)),
$array
)
);
Slightly different to your example output, but you can merge your inner arrays.
<?php
$data =
[
[
'animal' => [
'type' => 'fox'
],
[
'colour' => 'orange'
]
],
[
'animal' => [
'type' => 'panda'
],
[
'colour' => 'black and white'
]
]
];
$result =
array_map(
function($v) {
return array_merge($v['animal'], $v[0]);
},
$data
);
var_export($result);
Output:
array (
0 =>
array (
'type' => 'fox',
'colour' => 'orange',
),
1 =>
array (
'type' => 'panda',
'colour' => 'black and white',
),
)
If I understood you correctly you need to merge User array and in this case with the second array in that key. it that case something like this should work
foreach($array as $key=>$deep1){
$newArray = [];
foreach($deep1 as $deep2){
$newArray = array_merge($newArray,$deep2)
}
$array[$key] = $newArray;
}
Did II understand your question correctly?
I have an array which I'm sure there are some duplicate values in it, I want to search in this array and find the duplicate values and return the key of that array.
let me explain with an example, this is my array:
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 10
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => 4
],
2 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => 6
]
];
Now, I want to search in this array by name, family, and email at the same time and return the key of the parent (in this example 0 and 2). because I want to create a new array like this :
[
0 => [
'name' => 'name0',
'family' => 'family0',
'email' => 'email0#sample.com',
'rate' => [
10,
6
]
],
1 => [
'name' => 'name1',
'family' => 'family1',
'email' => 'email1#sample.com',
'rate' => [
4
]
],
];
How can I do this in PHP?
You can use array-reduce and use the 3 similar fields as keys.
Define a function who create the key and set or add rate:
function combineRate($carry, $item) {
$k = implode('###', array($item['name'], $item['family'], $item['email']));
if (isset($carry[$k]))
$carry[$k]['rate'][] = $item['rate'];
else {
$item['rate'] = [$item['rate']];
$carry[$k] = $item;
}
return $carry;
}
Call it with empty array:
$res = array_values(array_reduce($a, 'combineRate', array()));
Live example: 3v4l
How to set the default value of an array element if the key doesn't exist using filter_var_array():
var_dump(filter_var_array([], [
"page" => [
"filter" => FILTER_VALIDATE_INT,
"options" => [
"default" => 1,
"min_range" => 0
]
]
]));
//output: [ 'page' => null ];
Any idea set to [ 'page' => 1 ]?
The key must exist in the array in order to be validated (pass or fail). The third argument add_empty which defaults to true adds missing keys as NULL to the return value. This doesn't help as it would be nice to add it with the default value.
A common approach is to create the required keys that don't exist as NULL or preferably the default value. Your $array will overwrite the $required when they have common keys:
$array = [];
$required = ['page' => NULL]; //or 'page' => 1
$array = array_merge($required, $array);
var_dump(filter_var_array($array, [
"page" => [
"filter" => FILTER_VALIDATE_INT,
"options" => [
"default" => 1,
"min_range" => 0
]
]
]));
The only other way that I can see to do this is to add empties as NULL and then validate again to get the default value (not ideal):
$array = [];
var_dump($array = filter_var_array($array, [
"page" => [
"filter" => FILTER_VALIDATE_INT,
"options" => [
"default" => 1,
"min_range" => 0
]
]
]));
var_dump(filter_var_array($array, [
"page" => [
"filter" => FILTER_VALIDATE_INT,
"options" => [
"default" => 1,
"min_range" => 0
]
]
]));
Adds key with NULL value:
array(1) {
["page"]=>
NULL
}
Adds the default value:
array(1) {
["page"]=>
int(1)
}
I just add an array data and it worked
$data['page'] = NULL;
var_dump(filter_var_array($data, [
"page" => [
"filter" => FILTER_VALIDATE_INT,
"options" => [
"default" => 1,
"min_range" => 0
]
]
]));
?>