Replace elements in an associative array using another associative array - php

How can assign the values from one array to another array? For example:
//array with empty value
$targetArray = array(
'a' => '',
'b' => '',
'c' => '',
'd' => ''
);
// array with non-empty values, but might be missing keys from the target array
$sourceArray = array(
'a'=>'a',
'c'=>'c',
'd'=>'d'
);
The result I would like to see is the following:
$resultArray = array(
'a'=>'a',
'b'=>'',
'c'=>'c',
'd'=>'d'
);

I think the function you are looking for is array_merge.
$resultArray = array_merge($targetArray,$sourceArray);

Use array_merge:
$merged = array_merge($targetArray, $sourceArray);
// will result array('a'=>'a','b'=>'','c'=>'c','d'=>'d');

Use array_merge():
$targetArray = array('a'=>'','b'=>'','c'=>'','d'=>'');
$sourceArray = array('a'=>'a','c'=>'c','d'=>'d');
$result = array_merge( $targetArray, $sourceArray);
This outputs:
array(4) {
["a"]=>
string(1) "a"
["b"]=>
string(0) ""
["c"]=>
string(1) "c"
["d"]=>
string(1) "d"
}

Perhaps a more intuitive/indicative function for this task is array_replace(). It performs identically to array_merge() on associative arrays. (Demo)
var_export(
array_replace($targetArray, $sourceArray)
);
Output:
array (
'a' => 'a',
'b' => '',
'c' => 'c',
'd' => 'd',
)
A similar but not identical result can be achieved with the union operator, but notice that its input parameters are in reverse order and the output array has keys from $targetArray then keys from $sourceArray.
var_export($sourceArray + $targetArray);
Output:
array (
'a' => 'a',
'c' => 'c',
'd' => 'd',
'b' => '',
)

Related

PHP : Rename keys of associative array to the value of a child element when given the childs key name

Is there a PHP function I've missed that will change the keys of the parent array when given the key name of its child(associative array) or is there at least an alternative to a foreach loop which i am using at the moment to change the keys.
Example array
$arr = array(
array(
'id' => 1,
'name' => 'one',
),
array(
'id' => 2,
'name' => 'two',
),
array(
'id' => 3,
'name' => 'three',
)
);
I would like it to work like so..
$arr_name = array_change_key($arr,'name');
print_r($arr_name);
$arr_name => array(
'one', => array(
'id' => 1,
'name' => 'one',
),
'two' => array(
'id' => 2,
'name' => 'two',
),
'three' => array(
'id' => 3,
'name' => 'three',
)
);
//$arr is unchanged
This is just an added extra (not sure if possible)
array_change_key($arr,'name');
print_r($arr);
//$arr has changed because it doesn't have a variable to set
$arr => array(
'one', => array(
'id' => 1,
'name' => 'one',
),
'two' => array(
'id' => 2,
'name' => 'two',
),
'three' => array(
'id' => 3,
'name' => 'three',
)
);
print_r($arr[0]); //undefined index
If I understand the question correctly, something like:
$arr = array_combine(
array_column($arr, 'name'),
$arr
);
will use the name value from each record as the parent key, and give
array(3) {
["one"]=>
array(2) {
["id"]=>
int(1)
["name"]=>
string(3) "one"
}
["two"]=>
array(2) {
["id"]=>
int(2)
["name"]=>
string(3) "two"
}
["three"]=>
array(2) {
["id"]=>
int(3)
["name"]=>
string(5) "three"
}
}
You would have to tell the function whether or not to "pass by reference" it has no way of knowing whether you are trying to set the returned result to a variable;
function array_change_key(array &$array, $key, $pass_by_reference = false){
if($pass_by_reference){
// check is_scalar($key)
if(!is_scalar($key)) return FALSE;
// we already know isset($array), is_array($array) and isset(key) are true because $pass_by_reference is true;
$array = markBakersAnswer($array,$key);
return TRUE;
// pass-by-reference functions usually return true or false
}
return markBakersAnswer($array,$key);
}
MarkBakersAnswer +1
$new_array = array_change_key($arr, 'name'); // $arr unchanged and $new_array == array with new keys
$new_array = array_change_key($arr, 'name', false); // $arr unchanged and $new_array == array with new keys
$new_array = array_change_key($arr, 'name', true); // $arr changed (new keys), $new_array = TRUE;
$new_array = array_change_key($arr, array(), true); // $arr changed (new keys), $new_array = FALSE;

issue while merging two arrays using array_merge function

I have two associative array.
$Array1 = array(
'abc'=> 'abc',
'def'=> 'def'
);
$Array2 = array(
'123'=> '123',
'456'=> '456'
);
I am merging them using array_merge.
$Array3 = array_merge($Array1, $Array2);
Now value of $Array3 is like this.
Array
(
[abc] => abc
[def] => def
[0] => 123
[1] => 456
)
It looks really odd until I read php manual which says Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array. array_merge manual
My questing How can I merge both array without loosing their associative keys.
Both array can have common KEYS and I don't want to loose my information also. :(
By +:
$Array1 = array(
'abc'=> 'abc',
'def'=> 'def'
);
$Array2 = array(
'123'=> '123',
'456'=> '456'
);
var_dump($Array1 + $Array2);
This will preserve the index, but note this will not overwrite the value of the first array if same key exists in first array.
And if you want the overwrite working, then there is array_replace function for this:
var_dump(array_replace($Array1, $Array2));
Try this code :) it will work
function my_merge($array1,$array2)
{
foreach($array2 as $key => $value)
{
$array1[$key] = $value;
}
return $array1;
}
$Array1 = array(
'abc'=> 'abc',
'def'=> 'def'
);
$Array2 = array(
'123'=> '123',
'456'=> '456'
);
$Array3 = my_merge($Array1, $Array2);
For associative arrays, use
$result = $Array1 + $Array2;
-but note, that for numeric keys this will also re-index:
$Array1 = array(
'abc',
'def'=> 'def'
);
$Array2 = array(
'123',
'456'
);
var_dump($Array1 + $Array2);
//array(3) { [0]=> string(3) "abc" ["def"]=> string(3) "def" [1]=> string(3) "456" }
If you have same keys in your arrays, you can use:
$result = array_reduce(array_keys($Array1), function($c, $x) use ($Array1)
{
$c[$x] = isset($c[$x])
?array_merge((array)$c[$x], [$Array1[$x]])
:$Array1[$x];
return $c;
}, $Array2);

How to merge two arrays by taking over only values from the second array that has the same keys as the first one?

I'd like to merge two arrays with each other:
$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');
Whereas the merge should include all elements of $filtered and all those elements of $changed that have a corresponding key in $filtered:
$merged = array(1 => 'a', 3 => 'c*');
array_merge($filtered, $changed) would add the additional keys of $changed into $filtered as well. So it does not really fit.
I know that I can use $keys = array_intersect_key($filtered, $changed) to get the keys that exist in both arrays which is already half of the work.
However I'm wondering if there is any (native) function that can reduce the $changed array into an array with the $keys specified by array_intersect_key? I know I can use array_filter with a callback function and check against $keys therein, but there is probably some other purely native function to extract only those elements from an array of which the keys can be specified?
I'm asking because the native functions are often much faster than array_filter with a callback.
This should do it, if I'm understanding your logic correctly:
array_intersect_key($changed, $filtered) + $filtered
Implementation:
$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');
$expected = array(1 => 'a', 3 => 'c*');
$actual = array_key_merge_deceze($filtered, $changed);
var_dump($expected, $actual);
function array_key_merge_deceze($filtered, $changed) {
$merged = array_intersect_key($changed, $filtered) + $filtered;
ksort($merged);
return $merged;
}
Output:
Expected:
array(2) {
[1]=>
string(1) "a"
[3]=>
string(2) "c*"
}
Actual:
array(2) {
[1]=>
string(1) "a"
[3]=>
string(2) "c*"
}
if you want the second array ($b) to be the pattern that indicates that if there is only the key there, then you could also try this
$new_array = array_intersect_key( $filtered, $changed ) + $changed;
If your keys are non-numeric (which yours are not, so this is not a solution to your exact question), then you can use this technique:
$filtered = array('a' => 'a', 'c' => 'c');
$changed = array('b' => 'b*', 'c' => 'c*');
$merged = array_slice(array_merge($filtered, $changed), 0, count($filtered));
Result:
Array
(
[a] => a
[c] => c*
)
This works because for non-numeric keys, array_merge overwrites values for existing keys, and appends the keys in $changed to the end of the new array. So we can simply discard any keys from the end of the merged array more than the count of the original array.
Since this applies to the same question but with different key types I thought I'd provide it.
If you use this with numeric keys then the result is simply the original array ($filtered in this case) with re-indexed keys (IE as if you used array_values).

Moving array element to top in PHP

$arr = array(
'a1'=>'1',
'a2'=>'2'
);
I need to move the a2 to the top, as well as keep the a2 as a key how would I go on about it I can't seem to think a way without messing something up :)
Here is a solution which works correctly both with numeric and string keys:
function move_to_top(&$array, $key) {
$temp = array($key => $array[$key]);
unset($array[$key]);
$array = $temp + $array;
}
It works because arrays in PHP are ordered maps.
Btw, to move an item to bottom use:
function move_to_bottom(&$array, $key) {
$value = $array[$key];
unset($array[$key]);
$array[$key] = $value;
}
You can achieve that this way:
$arr = array(
'a1'=>'1',
'a2'=>'2'
);
end($arr);
$last_key = key($arr);
$last_value = array_pop($arr);
$arr = array_merge(array($last_key => $last_value), $arr);
/*
print_r($arr);
will output (this is tested):
Array ( [a2] => 2 [a1] => 1 )
*/
try this:
$key = 'a3';
$arr = [
'a1' => '1',
'a2' => '2',
'a3' => '3',
'a4' => '4',
'a5' => '5',
'a6' => '6'
];
if (isset($arr[ $key ]))
$arr = [ $key => $arr[ $key ] ] + $arr;
result:
array(
'a3' => '3',
'a1' => '1',
'a2' => '2',
'a4' => '4',
'a5' => '5',
'a6' => '6'
)
Here's a simple one liner to get this done with array_splice() and the union operator:
$arr = array('a1'=>'1', 'a2'=>'2', 'a3' => '3');
$arr = array_splice($arr,array_search('a2',array_keys($arr)),1) + $arr;
Edit:
In retrospect I'm not sure why I wouldn't just do this:
$arr = array('a2' => $arr['a2']) + $arr;
Cleaner, easier and probably faster.
You can also look at array_multisort This lets you use one array to sort another. This could, for example, allow you to externalize a hard-coded ordering of values into a config file.
<?php
$ar1 = array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);
var_dump($ar1);
var_dump($ar2);
?>
In this example, after sorting, the first array will contain 0, 10, 100, 100. The second array will contain 4, 1, 2, 3. The entries in the second array corresponding to the identical entries in the first array (100 and 100) were sorted as well.
Outputs:
array(4) {
[0]=> int(0)
[1]=> int(10)
[2]=> int(100)
[3]=> int(100)
}
array(4) {
[0]=> int(4)
[1]=> int(1)
[2]=> int(2)
[3]=> int(3)
}

Remove a set of fields from a array

Is there a native PHP function that can remove a set of keys from a array?
for eg. if I have a array like
array('a' => 'aaa', 'b' => 'bbb', 'c' => 'ccc', 'd' => 'ddd');
and I want to remove 'b', 'c' and get array('a' => 'aaa', 'd' => 'ddd'); ?
It's array_diff_key.
$input = array(...);
$remove = array_flip(array('a', 'b')); // 'a' and 'b' are the keys to remove
$output = array_diff_key($input, $remove);
See it in action.
$array = array('a', 'b', 'c', 'd')
foreach($array as $k=>$v){
if (in_array($v,array('b','c'))) unset($array[$k]);
}
An alternate to everyone else's answer, though all valid in their own way, is the array_splice function.
$foo = Array(
'a' => 'aaaa',
'b' => 'bbbb',
'c' => 'cccc',
'd' => 'dddd'
);
var_dump($foo);
array_splice($foo, 1, 2);
var_dump($foo);
Which produces:
array(4) {
["a"]=>
string(4) "aaaa"
["b"]=>
string(4) "bbbb"
["c"]=>
string(4) "cccc"
["d"]=>
string(4) "dddd"
}
array(2) {
["a"]=>
string(4) "aaaa"
["d"]=>
string(4) "dddd"
}
If you don't have too many fields to remove, you can use unset():
unset($foo['b']);
unset($foo['c']);
var_dump($foo)

Categories