Merge possible values to array when comparing two arrays - php

I'm looking for a simple solution to merge two arrays. They both look mostly alike, except one key-value-pair. I want my result to have an array with both possible values.
The xdebugged arrays look like this (simplified):
array (size=3)
'entry' => string '18' (length=2)
'mykey' => string 'value1' (length=6) // here is the difference
'something' => string '1' (length=1)
array (size=3)
'entry' => string '18' (length=2)
'mykey' => string 'value2' (length=6)) // here is the difference
'something' => string '1' (length=1)
I'd like the result to be:
array (size=2)
'entry' => string '18' (length=2)
'mykey' => array (size=2)) // both values merged to array
'0' => 'value1' (length=6)
'1' => 'value2' (length=6)
'something' => string '1' (length=1)
How to achieve this easily?

Would this suffice:
<?php
$array1 = array(
'entry'=>'18',
'mykey'=>'value1',
'something'=>'1'
);
$array2 = array(
'entry'=>'18',
'mykey'=>'value2',
'something'=>'1'
);
$output = array();
foreach($array1 as $k=>$v){
if(isset($array2[$k]) && $array2[$k] === $v){
$output[$k] = $v;
}elseif(isset($array2[$k])){
$output[$k][] = array($v,$array2[$k]);
}else{
$output[$k] = $v;
}
}
foreach($array2 as $k=>$v){
if(!array_key_exists($k,$output)){
$output[$k] = $v;
}
}
echo '<pre>',print_r($output),'</pre>';
Edit:I do like the use of array_merge_recursive() mentioned by Ziarno, but the issue is that it will create an array for each key. So I have added the use of array_unique(), then checking if the length is 1, and flattening it if so.
$output = array_merge_recursive($array1, $array2);
foreach($output as $k=>&$v){
$v = array_unique($v);
if(count($v)==1){
$v = $v[0];
}
}
echo '<pre>',print_r($output),'</pre>';

You need to write your own custom code for this.
// Get all the key values.
foreach($arrays as $array){
$keys[] = $array['mykey']
}
// retain 1st element & discard others.
$array = array_slice($arrays, 0, 1);
// update to the 1st array element
$array['mykey'] = $keys;
// print
print_r($array);
Hope this will help.

I think this function is designed exactly for what you need:
array_merge_recursive($array1, $array2)

Related

unset array keys if key is string

i have array something like this
$arr =
['0' =>
['0' => 'zero',
'1' => 'test',
'2' =>'testphp',
'test'=>'zero',
'test1'=>'test',
'test2'=>'testphp'],
'1' =>
['0' => 'z',
'1' => 'x',
'2' =>'c',
'test'=>'z',
'test1'=>'x',
'test2'=>'c']
];
and 0,1,2 is this same as test,test1,test2. I need remove keys where is string like test,test1,test2.
I know the way
foreach($arr as $a){
unset($arr['test']);
unset($arr['test1']);
unset($arr['test2']);
}
but it is possible find keys without specifying the exact name, because i want only number keys.
A solution would be:
Assuming you know it will only have 2 layers.
$arr =
['0' =>
['0' => 'zero',
'1' => 'test',
'2' =>'testphp',
'test'=>'zero',
'test1'=>'test',
'test2'=>'testphp'],
'1' =>
['0' => 'z',
'1' => 'x',
'2' =>'c',
'test'=>'z',
'test1'=>'x',
'test2'=>'c']
];
foreach($arr as $parentKey=>$arrayItem){
foreach($arrayItem as $key=>$subArrayItem){
if(!is_int($key)){
unset($arr[$parentKey][$key]);
}
}
}
var_dump($arr);
Why is it though that such arrays have been generated?
edit: after reading Valdorous answer realized it is multidimensional array. the following should handle recursively a multi-dimensional array.
call the function (see below)
remove_non_numeric_keys($arr)
function remove_non_numeric_keys($arr)
{
foreach($arr as $key=>$val)
{
if(!is_numeric($key)) // if not numeric unset it regardless if it is an array or not
{
unset($arr[$key]);
}else{
if(is_array($val) // if it is an array recursively call the function to check the values in it
{
remove_non_numeric_keys($val);
}
}
}
}
This should remove only non-numeric keys.
http://php.net/manual/en/function.is-numeric.php
Hope it helps

Array combined with another array - how to do this elegantly

I've got two arrays, an array of integers and an array of strings. I want to combine these two, but this is proving troublesome to me.
Basically, the first value in each array will be associated, the second value of each array will be associated, third with each other, and so on.
I've got a foreach loop iterating over and using $result as array key, as such:
foreach ($results as $result) {
And then a function to generate $order based on said string.
I am then trying to associate each value as I said, where I would have something like:
array('8' => 'value', '8' => 'value', '6' => 'anothervalue', '6' => 'anothervalue');
Here's the code I have.
$order = resource_library_apachesolr_resource_type_order($resource_type);
$result['resource_type'] = $resource_type;
$newresults = array($order => $result);
$order isn't iterating, so how would I make it so that I get the iterated value of $order combined with the currently iterating value of $result?
Well, since you have repeated keys, you can't use array_combine
You might have to get a bit creative. Maybe casting to string and adding 0 before the integer part...
EXAMPLE:
$a1 = array(1,1,2,3,3);
$a2 = array('a', 'b', 'c', 'd', 'e');
$a3 = array();
for ($i=0; $i<count($a1); ++$i) {
$key = (string) $a1[$i];
$val = (String) $a2[$i];
while (isset($a3[$key])) {
$key = "0$key";
}
$a3[$key] = $val;
}
var_dump($a3);
foreach ($a3 as $key => $val) {
$key = (int) $key;
print "$key=>$val<br>";
}
OUTPUTS:
array (size=5)
1 => string 'a' (length=1)
'01' => string 'b' (length=1)
2 => string 'c' (length=1)
3 => string 'd' (length=1)
'03' => string 'e' (length=1)
1=>a
1=>b
2=>c
3=>d
3=>e
I don't know why you need this, but if I want to do something like that I'll do:
$arr = array();
foreach($numbers as $i=>$num){
$arr[$num][] = $strings[$i];
}
and will get:
array(
1 => array(
a,
b
),
2 => array(
c
),
3 => array(
d,
e
)
)

replace array keys with given respective keys

I have an array like below
$old = array(
'a' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
I have another array having keys to replace with key information.
$keyReplaceInfoz = array('a' => 'newA', 'b' => 'newB', 'c' => 'newC', 'd' => 'newD');
I need to replace all keys of array $old with respective values in array $keyReplaceInfo.
Output should be like this
$old = array(
'newA' => 'blah',
'newB' => 'key',
'newC' => 'amazing',
'newD' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
I had to do it manually as below. I am expecting better option. can anyone suggest better way to accomplish this?
$new = array();
foreach ($old as $key => $value)
{
$new[$keyReplaceInfoz[$key]] = $value;
}
I know this can be more simpler.
array_combine(array_merge($old, $keyReplaceInfoz), $old)
I think this looks easier than what you posed.
array_combine(
['newKey1', 'newKey2', 'newKey3'],
array_values(['oldKey1' => 1, 'oldKey2' => 2, 'oldKey3' => 3])
);
This should do the trick as long as you have the same number of values and the same order.
IMO using array_combine, array_merge, even array_intersect_key is overkill.
The original code is good enough, and very fast.
Adapting #shawn-k solution, here is more cleaner code using array_walk, it will only replace desired keys, of course you can modify as per your convenience
array_walk($old, function($value,$key)use ($keyReplaceInfoz,&$old){
$newkey = array_key_exists($key,$keyReplaceInfoz)?$keyReplaceInfoz[$key]:false;
if($newkey!==false){$old[$newkey] = $value;unset($old[$key]);
}
});
print_r($old);
I just solved this same problem in my own application, but for my application $keyReplaceInfoz acts like the whitelist- if a key is not found, that whole element is removed from the resulting array, while the matching whitelisted keys get translated to the new values.
I suppose you could apply this same algorithm maybe with less total code by clever usage of array_map (http://php.net/manual/en/function.array-map.php), which perhaps another generous reader will do.
function filterOldToAllowedNew($key_to_test){
return isset($keyReplaceInfoz[$key_to_test])?$keyReplaceInfoz[$key_to_test]:false;
}
$newArray = array();
foreach($old as $key => $value){
$newkey = filterOldToAllowedNew($key);
if($newkey){
$newArray[$newkey] = $value;
}
}
print_r($newArray);
This question is old but since it comes up first on Google I thought I'd add solution.
// Subject
$old = array('foo' => 1, 'baz' => 2, 'bar' => 3));
// Translations
$tr = array('foo'=>'FOO', 'bar'=>'BAR');
// Get result
$new = array_combine(preg_replace(array_map(function($s){return "/^$s$/";},
array_keys($tr)),$tr, array_keys($old)), $old);
// Output
print_r($new);
Result:
Array
(
[FOO] => 1
[baz] => 2
[BAR] => 3
)
This the solution i have implemented for the same subject:
/**
* Replace keys of given array by values of $keys
* $keys format is [$oldKey=>$newKey]
*
* With $filter==true, will remove elements with key not in $keys
*
* #param array $array
* #param array $keys
* #param boolean $filter
*
* #return $array
*/
function array_replace_keys(array $array,array $keys,$filter=false)
{
$newArray=[];
foreach($array as $key=>$value)
{
if(isset($keys[$key]))
{
$newArray[$keys[$key]]=$value;
}
elseif(!$filter)
{
$newArray[$key]=$value;
}
}
return $newArray;
}
This works irrespective of array order & array count. Output order & value will be based on replaceKey.
$replaceKey = array('a' => 'newA', 'b' => 'newB', 'c' => 'newC', 'd' => 'newD', 'e' => 'newE','f'=>'newF');
$array = array(
'a' => 'blah',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
),
'noKey'=>'RESIDUAL',
'c' => 'amazing',
'b' => 'key',
);
$filterKey = array_intersect_key($replaceKey,$array);
$filterarray = array_intersect_key(array_merge($filterKey,$array),$filterKey);
$replaced = array_combine($filterKey,$filterarray);
//output
var_export($replaced);
//array ( 'newA' => 'blah', 'newB' => 'key', 'newC' => 'amazing', 'newD' => array ( 0 => 'want to replace', 1 => 'yes I want to' ) )
If you're looking for a recursive solution to use on a multidimensional array, have a look at the below method. It will replace all keys requested, and leave all other keys alone.
/**
* Given an array and a set of `old => new` keys,
* will recursively replace all array keys that
* are old with their corresponding new value.
*
* #param mixed $array
* #param array $old_to_new_keys
*
* #return array
*/
function array_replace_keys($array, array $old_to_new_keys)
{
if(!is_array($array)){
return $array;
}
$temp_array = [];
$ak = array_keys($old_to_new_keys);
$av = array_values($old_to_new_keys);
foreach($array as $key => $value){
if(array_search($key, $ak, true) !== false){
$key = $av[array_search($key, $ak)];
}
if(is_array($value)){
$value = array_replace_keys($value, $old_to_new_keys);
}
$temp_array[$key] = $value;
}
return $temp_array;
}
Using OP's example array:
$old = array(
'a' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' => array(
0 => 'want to replace',
1 => 'yes I want to'
)
);
$replace = ["a" => "AA", 1 => 11];
var_export(array_replace_keys($old, $replace));
Gives the following output:
array (
'AA' => 'blah',
'b' => 'key',
'c' => 'amazing',
'd' =>
array (
0 => 'want to replace',
11 => 'yes I want to',
),
)
DEMO
Inspired by the following snippet.
This uses #Summoner's example but keeps #Leigh's hint in mind:
$start = microtime();
$array = [ "a" => 1, "b" => 2, "c" => 3 ];
function array_replace_key($array, $oldKey, $newKey) {
$keys = array_keys($array);
$idx = array_search($oldKey, $keys);
array_splice($keys, $idx, 1, $newKey);
return array_combine($keys, array_values($array));
}
print_r(array_replace_key($array, "b", "z"));
<?php
$new = array();
foreach ($old as $key => $value)
{
$new[$keyReplaceInfoz][$key] = $value;
}
?>

Combining two arrays by ID in PHP [duplicate]

This question already has answers here:
Merge two indexed arrays of indexed arrays based on first column value
(2 answers)
Closed 5 months ago.
I need to compare two 2D arrays in PHP. The arrays look like this:
Array one
ID Name
11 Aa
11 Ab
12 Bb
13 Cc
14 Dd
15 Ee
Array two
ID Content
11 Cat
13 Dog
14 Donkey
Now I'd need to combine these two into an array like this:
ID Name Conent
11 Aa Cat
11 Ab Cat
12 Bb
13 Cc Dog
14 Dd Donkey
15 Ee
How can I accomplish this? I have had no luck with array_merge() or $array3 = $array1 + $array2;
A quick way would be to iterate over the first array and append the value from the second:
$array1 = array('11' => 'Aa', '12' => 'Bb', '13' => 'Cc', '14' => 'Dd', '15' => 'Ee');
$array2 = array('11' => 'Cat', '13' => 'Dog', '14' => 'Donkey');
$combined = array();
foreach ($array1 as $key => $val) {
$combined[$key] = $val . (isset($array2[$key]) ? ' '.$array2[$key] : '');
}
This will loop through every key/value in $array1 and add it to the $combined array. If a value in $array2 exists with the same index, it will append it to that value from $array1, separated with a space.
UPDATE: I misread the format of the arrays (again). I assumed ID was the actual index in the array, but as the example array output has both Name and Content, I'm assuming ID is an actual index string value and not the index in the array itself. To stick with the loop scenario, you can iterate through the first array and have a nested loop iterate through the second:
$array1 = array(
array('ID' => '11', 'Name' => 'Aa'),
array('ID' => '12', 'Name' => 'Bb'),
array('ID' => '13', 'Name' => 'Cc'),
array('ID' => '14', 'Name' => 'Dd'),
array('ID' => '15', 'Name' => 'Ee'),
);
$array2 = array(
array('ID' => '11', 'Content' => 'Cat'),
array('ID' => '13', 'Content' => 'Dog'),
array('ID' => '14', 'Content' => 'Donkey')
);
$combined = array();
foreach ($array1 as $arr) {
$comb = array('ID' => $arr['ID'], 'Name' => $arr['Name'], 'Content' => '');
foreach ($array2 as $arr2) {
if ($arr2['ID'] == $arr['ID']) {
$comb['Content'] = $arr2['Content'];
break;
}
}
$combined[] = $comb;
}
This will add every value in $array1 to the combined array and if, and only if, a value in $array2 contains the same ID field will it add it's Content field to the array too. This can be extended to handle any number of fields as well, either by name, or by changing the inner-if block to have $comb += $arr2; instead (which should merge all non-existing indexes).
You will have to make your own function:
function putThemTogether($array1, $array2) {
$output = array();
foreach($array1 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
foreach($array2 as $key => $value) {
if (!isset($output[$key]))
$output[$key] = array();
$output[$key][] = $value;
}
return $output;
}
To make this better you could make it take an arbitrary number of arguments.
$result = array_map (
function ($item) { return is_array($item) ? implode(' ', $item) : $item; },
array_merge_recursive($array1, $array2);
);
Note, that both arrays require string keys
Another solution for this is to use array_search and array_column (since PHP 5.5.0).
foreach ($array1 as $key => $val) {
$found_key = array_search($val['ID'], array_column($array2, 'ID'));
if ($found_key !== false) { $array1[$key]['Content'] = $array2[$found_key]['Content']; }
}
Try this I hope It'll work
function merge_two_arrays($array1,$array2) {
$data = array();
$arrayAB = array_merge($array1,$array2);
foreach ($arrayAB as $value) {
// This assumes there is a field called "id"
$id = $value['id'];
if (!isset($data[$id])) {
$data[$id] = array();
}
$data[$id] = array_merge($data[$id],$value);
}
return $data;
}
$master_array = merge_two_arrays($array1,$array2);

shift all array elements up one level in a multidimensional array

I have an array that may look like
$arr = array(
array(
'test1' => 'testing1'
),
array(
'test2' => array(
1 =>'testing2
)
);
and I want to turn it into
$newArr = array(
'test1' => 'testing1',
'test2' => array(
1 => 'testing2'
)
);
so i have been trying to shift all array elements up one level.
eidt:
this is my method that combines 2 array together:
public function arrayMerge($arr1, $arr2)
{
foreach($arr2 as $key => $value) {
$condition = (array_key_exists($key, $arr1) && is_array($value));
$arr1[$key] = ($condition ? $this->arrayMerge($arr1[$key], $arr2[$key]) : $value);
}
return $arr1;
}
It's somewhat trivial, many ways are possible.
For example using the array union operator (+)­Docs creating the union of all arrays inside the array:
$newArr = array();
foreach ($arr as $subarray)
$newArr += $subarray;
Or by using array_merge­Docs with all subarrays at once via call_user_func_array­Docs:
$newArray = call_user_func_array('array_merge', $arr);
Try
$arr = array(
array('test1' => 'testing1' ),
array('test2' => array(1 =>'testing2'))
);
$new = array();
foreach($arr as $value) {
$new += $value;
}
var_dump($new);
Output
array
'test1' => string 'testing1' (length=8)
'test2' =>
array
1 => string 'testing2' (length=8)

Categories