Replace values of one array based on a mapping array - php

I have two arrays:
$array1 = [29, 'a', 'x', 'c', 11];
$array2 = ['a' => 20, 'x' => 21, 'c' => 23];
I want to get an array that looks like:
$array3 = [29, 20, 21, 23, 11];
I know how to do it with a foreach loop, but I was wondering if there was a way to do it as a one liner, or maybe with some sort of anonymous function.

array_map work as well the other answer :
$array1 = [29, 1=>'a', 2=>'x',3=>'c', 11];
$array2 = ['a'=>20, 'x'=>21, 'c'=>23];
$array3 = array_map(function($a) use($array2){return is_int($a) ? $a : $array2[$a];}, $array1);

You can add them and filter out non-numeric values:
$array3 = array_values(array_filter($array1 + $array2, 'is_numeric'));
If the order is important:
$array3 = array_filter(call_user_func_array(
'array_merge', array_map(null, $array1, $array2)),
'is_numeric');
Then array_values if you need to re-index.
In either case, if you want only integers or floats then use is_int or is_float.

An attempt with a one-liner :
$array1 = [29, 1=>'a', 2=>'x',3=>'c', 11];
$array2 = ['a'=>20, 'x'=>21, 'c'=>23];
$array3 = array_values(array_filter(array_merge($array1,$array2),function($i){return is_int($i);}));
print_r($array3);
// Outputs :
/*
Array
(
[0] => 29
[1] => 11
[2] => 20
[3] => 21
[4] => 23
)
*/

I reckon this looks more elegant than the earlier posted solutions...
Code: (Demo)
var_export(
array_map(fn($v) => $array2[$v] ?? $v, $array1)
);
Attempt to access the mapping array's value by key; if there is no matching key, then default to the original value.

If you don't like to use foreach() you can use array_replace() function. You can learn more about this function in below:
Array_replace($array1 , $array2, $...) in php.net

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);

Get all the keys presented in all arrays

I have some arrays, for example
$arr[0]=array(k1=>1,k2=>1,k3=>1);
$arr[1]=array(k2=>1,k3=>1,k4=>1);
$arr[2]=array(k3=>1,k4=>1,k5=>1);
So, I need to get all the keys (dynamically, the number of arrays can differ), presented in all arrays. In this case it is k3 key. So the result should be array('k3'=>1)
I suggest it could be achieved by multiple loops, but probably there's some easier way.
You need the function array_intersect_key():
<?php
$arr1 = array('k1' => 1, 'k2' => 1, 'k3' => 1);
$arr2 = array('k2' => 1, 'k3' => 1, 'k4' => 1);
$arr3 = array('k3' => 1, 'k4' => 1, 'k5' => 1);
print_r(
array_intersect_key($arr1, $arr2, $arr3)
);
Output:
Array
(
[k3] => 1
)
To get the common elements in three arrays, you can use array_intersect()
Note: This function works on common array values and not common array keys
Try this:
$key1 = array_flip($arr1);
$key2 = array_flip($arr1);
$key3 = array_flip($arr1);
$intersect = array_flip(array_intersect($key1, $key2, $key3));

How to swap two values in array with indexes?

For example i have an array like this $array = ('a' => 2, 'b' => 1, 'c' => 4); and i need to swap a with c to get this $array = ('c' => 4, 'b' => 1, 'a' => 2);. Wht is the best way for doing this without creating new array? I know that it is possible with XOR, but i also need to save indexes.
array_splice would be perfect, but unfortunately it doesn't preserve the keys in the inserted arrays. So you'll have to resort to a little more manual slicing and dicing:
function swapOffsets(array $array, $offset1, $offset2) {
list($offset1, $offset2) = array(min($offset1, $offset2), max($offset1, $offset2));
return array_merge(
array_slice($array, 0, $offset1, true),
array_slice($array, $offset2, 1, true),
array_slice($array, $offset1 + 1, $offset2 - $offset1 - 1, true),
array_slice($array, $offset1, 1, true),
array_slice($array, $offset2 + 1, null, true)
);
}
If you want to purely swap the first and the last positions, here's one way to do it:
$first = array(key($array) => current($array)); // Get the first key/value pair
array_shift($array); // Remove it from your array
end($array);
$last = array(key($array) => current($array)); // Get the last key/value pair
array_pop($array); // Remove it from the array
$array = array_merge($last, $array, $first); // Put it back together
Gives you:
Array
(
[c] => 4
[b] => 1
[a] => 2
)
Working example: http://3v4l.org/r87qD
Update: And just for fun, you can squeeze that down quite a bit:
$first = array(key($array) => current($array));
$last = array_flip(array(end($array) => key($array)));
$array = array_merge($last, array_slice($array,1,count($array) - 2), $first);
Working example: http://3v4l.org/v6R7T
Update 2:
Oh heck yeah, we can totally do this in one line of code now:
$array = array_merge(array_flip(array(end($array) => key($array))), array_slice($array,1,count($array) - 2), array_flip(array(reset($array) => key($array))));
Working example: http://3v4l.org/QJB5T
That was fun, thanks for the challenge. =)

php. array_values function. how to get mapping from old keys to new keys?

There is function array_values in PHP such that
$array2 = array_values($array1);
$array2 has the same values as $array1 but keys are from
0 to sizeof($array1) - 1. Is it possible to get mapping from old keys to new keys?
EDIT. I will explain on an example:
$array1 = array( 'a' => 'val1', 'b' => 'val1');
$array2 = array_values( $array1 );
so now array2 has next values
$array2[0] = 'val1'
$array2[1] = 'val2'
How get array3 such that:
$array3['a'] = 0
$array3['b'] = 1
To produce a key map you need to first get the keys into a regular array and then flip the keys and values:
$array1_keymap = array_flip(array_keys($array1));
For example:
$array1 = array(
'a' => 123,
'b' => 567,
);
$array1_values = array_values($array1);
$array1_keymap = array_flip(array_keys($array1));
Value of $array1_values:
array(
0 => 123,
1 => 567,
);
Value of $array1_keymap:
array(
'a' => 0,
'b' => 1,
);
So:
$array1['a'] == $array1_values[$array1_keymap['a']];
$array1['b'] == $array1_values[$array1_keymap['b']];
Yes, as simple as
$array2 = $array1;
In this case you would get both values and keys like they are in the original array.
$keyMapping = array_combine(array_keys($array1), array_keys($array2));
This the keys of $array1 and maps them to the keys of $array2 like so
<?php
$array1 = array(
'a' => '1',
'b' => '2',
);
$array2 = array_values($array1);
print_r(array_combine(array_keys($array1), array_keys($array2)));
Array
(
[a] => 0
[b] => 1
)
You can use:
$array3 = array_keys($array1);
Now $array3[$n] is the key of the value in $array2[$n] for any 0 <= $n < count($array1). You can use this to determine which keys were in which places.
If you want to keep the same value of array1 but change the key to index numbers, try this:
$array2 = array();
foreach ($array1 as $key => $value){
$array2[] = $value;
// or array_push($array2, $value);
}
var_dump($array2);

reaarange array after deleting its element

hi
i have array like $arr with 10 elements when i unset the 5 element and print the array it print he array without 5 indx. now i want to rearrange the array with 9 elements and first four values index will be same but after this values should be shifted to (previous index-1).
is there any simple method is there (array function). or i have to made a complete logic for this.
Well, if you want to maintain order, but just want to re-index the keys, you can use the array_values() function.
$a = array(
0 => 'a',
1 => 'b',
2 => 'c',
3 => 'd'
);
unset($a[1]);
$a = array(
0 => 'a',
2 => 'c',
3 => 'd'
); // Note, this is what $a is now, the re-assignment is for illustration only
$a = array_values($a);
$a = array(
0 => 'a',
1 => 'c',
2 => 'd'
); // Note, this is what $a is now, the re-assignment is for illustration only
You should use array_splice, rather than unset, to remove the elements from the array. Doing so will reorder the remaining elements:
$input = array("red", "green", "blue", "yellow");
array_splice($input, 1, 1);
// $input is now array("red", "blue", "yellow")
Not too sure if there's a better way but you can use array_reverse(), twice:
$array = array_reverse($array, false);
$array = array_reverse($array, false);

Categories