How to add array keys to the same array? - php

I have an array like this:
[
'one' => ['whatever'=>'something','whatever1'=>'something1'],
'two' => ['whatever'=>'something','whatever1'=>'something1'],
'three' => ['whatever'=>'something','whatever1'=>'something1'],
]
and now I wanna add the array keys to the same array with a specific key like below:
[
'one' => ['name'=>'one', 'whatever'=>'something','whatever1'=>'something1'],
'two' => ['name'=>'two', 'whatever'=>'something','whatever1'=>'something1'],
'three' => ['name'=>'three', 'whatever'=>'something','whatever1'=>'something1'],
]
I can handle this with foreach() but is there no function in PHP that can do this or in a shorter way?

Yes there is are lot of functions for array handling, if you are the starter then you have to do with foreach.
If you have an array named $array , then you can try this-
$array = array_map(function (array $arr, $arr_key) { return $arr + array('name' => $arr_key); }, $array, array_keys($array));

Related

how to fix array_udiff while having strings inside array [duplicate]

I have an array containing rows of associative data.
$array1 = array(
array('ITEM' => 1),
array('ITEM' => 2),
array('ITEM' => 3),
);
I have a second array, also containing rows of associative data, that I would like to filter using the first array.
$array2 = array(
array('ITEM' => 2),
array('ITEM' => 3),
array('ITEM' => 1),
array('ITEM' => 4),
);
This feels like a job for array_diff(), but how can I compare the rows exclusively on the deeper ITEM values?
How can I filter the second array and get the following result?
array(3 => array('ITEM' => 4))
You can define a custom comparison function using array_udiff().
function udiffCompare($a, $b)
{
return $a['ITEM'] - $b['ITEM'];
}
$arrdiff = array_udiff($arr2, $arr1, 'udiffCompare');
print_r($arrdiff);
Output:
Array
(
[3] => Array
(
[ITEM] => 4
)
)
This uses and preserves the arrays' existing structure, which I assume you want.
I would probably iterate through the original arrays and make them 1-dimensional... something like
foreach($array1 as $aV){
$aTmp1[] = $aV['ITEM'];
}
foreach($array2 as $aV){
$aTmp2[] = $aV['ITEM'];
}
$new_array = array_diff($aTmp1,$aTmp2);
Another fun approach with a json_encode trick (can be usefull if you need to "raw" compare some complex values in the first level array) :
// Compare all values by a json_encode
$diff = array_diff(array_map('json_encode', $array1), array_map('json_encode', $array2));
// Json decode the result
$diff = array_map('json_decode', $diff);
A couple of solutions using array_filter that are less performant than the array_udiff solution for large arrays, but which are a little more straightforward and more flexible:
$array1 = [
['ITEM' => 1],
['ITEM' => 2],
['ITEM' => 3],
];
$array2 = [
['ITEM' => 2],
['ITEM' => 3],
['ITEM' => 1],
['ITEM' => 4],
];
$arrayDiff = array_filter($array2, function ($element) use ($array1) {
return !in_array($element, $array1);
});
// OR
$arrayDiff = array_filter($array2, function ($array2Element) use ($array1) {
foreach ($array1 as $array1Element) {
if ($array1Element['ITEM'] == $array2Element['ITEM']) {
return false;
}
}
return true;
});
As always with array_filter, note that array_filter preserves the keys of the original array, so if you want $arrayDiff to be zero-indexed, do $arrayDiff = array_values($arrayDiff); after the array_filter call.
you can use below code to get difference
$a1 = Array(
[0] => Array(
[ITEM] => 1
)
[1] => Array(
[ITEM] => 2
)
[2] => Array(
[ITEM] => 3
)
);
$a2 = Array(
[0] => Array(
[ITEM] => 2
)
[1] => Array(
[ITEM] => 3
)
[2] => Array(
[ITEM] => 1
)
[3] => Array(
[ITEM] => 4
));
array_diff(array_column($a1, 'ITEM'), array_column($a2, 'ITEM'));
Having the same problem but my multidimensional array has various keys unlike your "ITEM" consistently in every array.
Solved it with: $result = array_diff_assoc($array2, $array1);
Reference: PHP: array_diff_assoc
Another solution
if( json_encode($array1) == json_encode($array2) ){
...
}
Trust that the maintainers of PHP have optimized array_udiff() to outperform all other techniques which could do the same.
With respect to your scenario, you are seeking a filtering array_diff() that evaluates data within the first level's "value" (the row of data). Within the custom function, the specific column must be isolated for comparison. For a list of all native array_diff() function variations, see this answer.
To use the first array to filter the second array (and output the retained data from the second array), you must write $array2 as the first parameter and $array1 as the second parameter.
array_diff() and array_intersect() functions that leverage (contain u in their function name) expect an integer as their return value. That value is used to preliminary sort the data before actually performing the evaluations -- this is a performance optimization. There may be scenarios where if you only return 0 or 1 (not a three-way comparison), then the results may be unexpected. To ensure a stable result, always provide a comparison function that can return a negative, a positive, and a zero integer.
When comparing integer values, subtraction ($a - $b) will give reliable return values. For greater utility when comparing float values or non-numeric data, you can use the spaceship operator when your PHP version makes it available.
Codes: (Demo)
PHP7.4+ (arrow functions)
var_export(
array_udiff($array2, $array1, fn($a, $b) => $a['ITEM'] <=> $b['ITEM'])
);
PHP7+ (spaceship operator)
var_export(
array_udiff(
$array2,
$array1,
function($a, $b) {
return $a['ITEM'] <=> $b['ITEM'];
}
)
);
PHP5.3+ (anonymous functions)
var_export(
array_udiff(
$array2,
$array1,
function($a, $b) {
return $a['ITEM'] === $b['ITEM']
? 0
: ($a['ITEM'] > $b['ITEM'] ? 1 : -1);
}
)
);
Output for all version above:
array (
3 =>
array (
'ITEM' => 4,
),
)
When working with object arrays, the technique is the same; only the syntax to access a property is different from accessing an array element ($a['ITEM'] would be $a->ITEM).
For scenarios where the element being isolated from one array does not exist in the other array, you will need to coalesce both $a and $b data to the opposite fallback column because the data from the first array and the second arrays will be represented in both arguments of the callback.
Code: (Demo)
$array1 = array(
array('ITEM' => 1),
array('ITEM' => 2),
array('ITEM' => 3),
);
$array2 = array(
array('ITEMID' => 2),
array('ITEMID' => 3),
array('ITEMID' => 1),
array('ITEMID' => 4),
);
// PHP7.4+ (arrow functions)
var_export(
array_udiff(
$array2,
$array1,
fn($a, $b) => ($a['ITEM'] ?? $a['ITEMID']) <=> ($b['ITEM'] ?? $b['ITEMID'])
)
);
Compares array1 against one or more other arrays and returns the values in array1 that are not present in any of the other arrays.
//Enter your code here, enjoy!
$array1 = array("a" => "green", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);
print_r($result);

array_replace_recursive() without creation of keys

In PHP, array_replace_recursive() does two things according to the documentation:
If a key from the first array exists in the second array, its value will be replaced by the value from the second array.
If the key exists in the second array, and not the first, it will be created in the first array.
Is there an alternative that only does the replacement, and doesn't create new keys?
For example:
$array = [
'apple' => TRUE,
'pear' => TRUE,
'basket' => [
'banana' => TRUE,
],
'punnet' => [
'strawberry' => TRUE,
],
];
$replacement = [
'banana' => [
'REPLACEMENT!'
],
];
The result should be:
$array = [
'apple' => TRUE,
'pear' => TRUE,
'basket' => [
'banana' => [
'REPLACEMENT!'
],
],
'punnet' => [
'strawberry' => TRUE,
],
];
You will need to use array_intersect_key() to create an array that contains only the keys that are in the two arrays, then you can merge.
$array1 = [
'a' => 1,
'b' => 2,
'c' => 3,
'd' => 4,
];
$array2 = [
'b' => 14,
'c' => 70,
'f' => 5,
];
// $array2 has to be the first arguments for $inter to have its value instead of the value of $array1
$inter = array_intersect_key($array2, $array1);
$merged = array_replace_recursive($array1, $inter);
// Merged will be:
[
'a' => 1,
'b' => 14,
'c' => 70,
'd' => 4,
];
array_intersect_key
EDIT
For this to work recursively, you can use this function found here
/**
* Recursively computes the intersection of arrays using keys for comparison.
*
* #param array $array1 The array with master keys to check.
* #param array $array2 An array to compare keys against.
* #return array associative array containing all the entries of array1 which have keys that are present in array2.
**/
function array_intersect_key_recursive(array $array1, array $array2) {
$array1 = array_intersect_key($array1, $array2);
foreach ($array1 as $key => &$value) {
if (is_array($value) && is_array($array2[$key])) {
$value = array_intersect_key_recursive($value, $array2[$key]);
}
}
return $array1;
}
If you don't like creation of non existant keys, you can use array_replace_recursive() as is and then you can roll out your own recursive version which would remove all extra keys. You may however roll out your own recursive replace version instead of the below 2 pass solution, but I would prefer the below described to avoid re-inventing the wheel of array_replace_recursive()(since you know what the wheel is about).
function removeNonExistantKeys(&$basket,&$base){
$keys = array_diff_key($basket, $base);
foreach($keys as $unwanted_key => $value){
unset($basket[ $unwanted_key ]);
}
foreach($basket as $key => &$value){
if(is_array($value) && is_array( $base[ $key ] )){
removeNonExistantKeys($value , $base[ $key ]);
}
}
}
We use & references wherever needed to edit the same copy of the array.
The above function uses array_diff_key to find difference between 2 sets of array in terms of keys and unsets all of them in the next foreach.
We then walk recursively to both modified and initial arrays into it's sub children performing the same task.
Driver code:
<?php
$base = array('citrus' => array( "orange") , 'berries' => array("blackberry", "raspberry"),'a' => ['b' => 'f']);
$replacements = array('citrus' => array('pineapple'), 'berries' => array('blueberry'),'a' => ['b' => 'd','e' => 'ab']);
$basket = array_replace_recursive($base, $replacements);
function removeNonExistantKeys(&$basket,&$base){
$keys = array_diff_key($basket, $base);
foreach($keys as $unwanted_key => $value){
unset($basket[ $unwanted_key ]);
}
foreach($basket as $key => &$value){
if(is_array($value) && is_array( $base[ $key ] )){
removeNonExistantKeys($value , $base[ $key ]);
}
}
}
removeNonExistantKeys($basket,$base);
print_r($basket);
This does what I needed:
array_walk_recursive($array, function(&$value, $key, $replacements) {
if (isset($replacements[$key])) {
$value = $replacements[$key];
}
}, ['replace' => 'replacement']);

pass value of sub-array to key

I have this array :
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
And I would like to obtain this one :
array(
'AMO' => array(),
'PAT' => array()
)
How could I do this, in the shortest way possible ?
I can do it with an array_map, followed by an array_flip and next an array_walk .. but too long.
array_column to extract the keys and array_fill_keys to create the new array:
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
$res = array_fill_keys(array_column($arr, 'id'), []);
simply loop over array and make its id to new array key
$arr = array(0 => array('id' => "AMO"), 1 => array('id' => "PAT"));
foreach($arr as $value)
{
$new_arr[$value['id']] = array();
}
print_r($new_arr);
DEMO
I dont know what is the logic behind this, but you can try this one.
Here we are using array_combine, array_keys and array_fill
Try this code snippet here
$result= array_combine(
array_column($array,"id"),//getting column id
array_fill(0, count($array), array())//mapping that keys with empty array
);

How can I group array values into a new array?

I've got an array like this:
$a = [
'53' => ['Foo', 1],
'234' => ['Bar', 12],
'343' => ['Bar', 22],
'3' => ['Qux', 12],
'34' => ['Foo', 1],
...]
I want to create an array that looks like this:
['1' => ['Foo', 'Foo'],
'12' => ['Bar', 'Qux']
'22' => ['Bar']]
That is, I want to look at the second element of each element in $a, and produce an array that uses this second element as an index in a new array, with the first element values added together in an array.
Hope this makes sense, there's probably a nice way to do it but my PHP array knowledge is somewhat lacking.
$result = array();
foreach($a as $value) {
$result[$value[1]][] = $value[0];
}

How can I efficiently split an array into its associative key arrays?

How can I split a single array into it's sub-keys?
$arr = array(
0 => array(
'foo' => '1',
'bar' => 'A'
),
1 => array(
'foo' => '2',
'bar' => 'B'
),
2 => array(
'foo' => '3',
'bar' => 'C'
)
);
What is the most efficient way to return an array of foo and bar separately?
I need to get here:
$foo = array('1','2','3');
$bar = array('A','B','C');
I'm hoping there's a clever way to do this using array_map or something similar. Any ideas?
Or do I have to loop through and build each array that way? Something like:
foreach ($arr as $v) {
$foo[] = $v['foo'];
$bar[] = $v['bar'];
}
In a lucky coincidence, I needed to do almost the exact same thing earlier today. You can use array_map() in combination with array_shift():
$foo = array_map('array_shift', &$arr);
$bar = array_map('array_shift', &$arr);
Note that $arr is passed by reference! If you don't do that, then each time it would return the contents of $arr[<index>]['foo']. However, again because of the reference - you won't be able to reuse $arr, so if you need to do that - copy it first.
The downside is that your array keys need to be ordered in the same way as in your example, because array_shift() doesn't actually know what the key is. It will NOT work on the following array:
$arr = array(
0 => array(
'foo' => '1',
'bar' => 'A'
),
1 => array(
'bar' => 'B',
'foo' => '2'
),
2 => array(
'foo' => '3',
'bar' => 'C'
)
);
Update:
After reading the comments, it became evident that my solution triggers E_DEPRECATED warnings for call-time-pass-by-reference. Here's the suggested (and accepted as an answer) alternative by #Baba, which takes advantage of the two needed keys being the first and last elements of the second-dimension arrays:
$foo = array_map('array_shift', $arr);
$bar = array_map('array_pop', $arr);
$n = array();
foreach($arr as $key=>$val) {
foreach($val as $k=>$v) {
$n[$k][] = $v;
}
}
array_merge_recursive will combine scalar values with the same key into an array. e.g.:
array_merge_recursive(array('a',1), array('b',2)) === array(array('a','b'),array(1,2));
You can use this property to simply apply array_merge_recursive over each array in your array as a separate argument:
call_user_func_array('array_merge_recursive', $arr);
You will get this result:
array (
'foo' =>
array (
0 => '1',
1 => '2',
2 => '3',
),
'bar' =>
array (
0 => 'A',
1 => 'B',
2 => 'C',
),
)
It won't even be confused by keys in different order.
However, every merged value must be scalar! Arrays will be merged instead of added as a sub-array:
array_merge_recursive(array(1), array(array(2)) === array(array(1,2))
It does not produce array(array(1, array(2)))!

Categories