how do I merge two arrays, and just increase the values when the keys match?
Both the arrays might contain keys that does not exists in the other, and both of them might have more or less keys than the other.
So I cannot just take one array, and loop trough that and compare with the other since some times the "other" array might have more values. This swithces from time to time.
Array merge doesn't seem to be working either since it overwrites the old value.
I need to return all unique keys from both arrays, but but whenever a key matches, I need to just add the two values together.
Array_a:
["BMW-B2"]=>int(1)
["BMW-N-115 "]=>int(5)
["BMW-N-143"]=>int(3)
["BMW-N-163"]=>int(10)
["BMW-N-184"]=>int(4)
Array_b
["CR220036"]=>int(3)
["BMW-N-163"]=>int(9)
["CR220822"]=>int(7)
Array_merged
["BMW-B2"]=>int(1)
["CR220036"]=>int(3)
["CR220822"]=>int(7)
["BMW-N-115 "]=>int(5)
["BMW-N-143"]=>int(3)
["BMW-N-163"]=>int(19) // <-- this has increast by 9
["BMW-N-184"]=>int(4)
The order is not important.
You can achieve this by using a loop and and merging the arrays. Basically, you pick one array that you will check for duplicate values, perform your arithmetic, unset the no longer needed array elements, and then merge it all together.
Consider adapting your code similar to the following:
$array1 = array("val1" => 5, "val2" => 8, "val3" => 10, "val4" => 2, "val5" => 12);
$array2 = array("val3" => 9, "val6" => 11, "val1" => 15);
foreach ($array2 as $key => $value)
{
if (array_key_exists($key, $array1))
{
$array1[$key] += $value;
unset($array2[$key]);
}
}
$merged = array_merge($array1, $array2);
var_dump($merged);
//Output:
array(6) {
["val1"]=>
int(20)
["val2"]=>
int(8)
["val3"]=>
int(19)
["val4"]=>
int(2)
["val5"]=>
int(12)
["val6"]=>
int(11)
}
In my example, all the values in $array2 are compared with $array1 to locate duplicate keys and increment by the stored value. If a dupe is found then that element is unset, this will prevent the modified keys in $array1 from being overwritten in the array_merge() operation.
How about this:
$arr1=array(1,2,3,4);
$arr2=array(1,2,5=>1);
$result=array();
foreach($arr1 as $k=>$v){
$result[$k]=$v;
if(isset($arr2[$k])){
$result[$k]+=$arr2[$k];
}
}
foreach($arr2 as $k=>$v){
if(!isset($result[$k]){
$result[$k]=$v;
}
}
var_dump($result);
Related
I think this should be something simple, but I can't find a way to do it.
I have two arrays, one with colors and ids
$color_ids = [
'green' => [1,2,3],
'blue' => [4,5],
'red' => [6],
'pink' => [7,8,9],
'yellow' => [10]
];
and others with selection.
$select = ['green', 'red', 'yellow'];
Then I need the ids where intersects keys between $color_ids and $select. This should be the result (a simple linear array):
$results = [1,2,3,6,10];
I've tried this:
$result = array_values(array_intersect_key( $color_ids, array_flip($select ) ) );;
But I get multidimensional array:
array(3) {
[0]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) }
[1]=> array(1) { [0]=> int(6) }
[2]=> array(1) { [0]=> int(10) }
}
I get the same result with this:
$result = [];
foreach ($select as $key) {
if (isset($color_ids[$key]))
$result[] = $color_ids[$key];
}
How can I get a simple linear array with ids?
1) Iterate over the key array
2) Merge all the arrays into one using array_merge
$select = ['green', 'red', 'yellow'];
$finalArray=[];
foreach($select as $value){
$finalArray= array_merge($finalArray,$color_ids[$value]);
}
echo "<pre>";
print_r($finalArray);
Output:
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 6
[4] => 10
)
You can use array_merge with the ... operator which is a common flattening technique demonstrated here.
array_merge(...$result);
Array Merge documentation.
Splat Operator documentation.
with foreach
$result = [];
foreach($color_ids as $color => $ids){
$result = array_merge($result, in_array($color, $select) ? $ids : []);
}
If you are looking for a fully "functional style" solution, here's one.
Set up your filtering array ($select) so that it has keys like the master array's keys. In other words, flip the values into keys.
Then swiftly filter the master array using array_intersect_key().
Then to flatten the remaining data, prepend the splat/spread operator and call array_merge().
Until you are on a php version that allows associative arrays to be spread, then you'll need to call array_values() to reindex the first level keys so that the spread operator doesn't choke.
Code: (Demo)
var_export(
array_merge(
...array_values(
array_intersect_key(
$color_ids,
array_flip($select)
)
)
)
);
Or if you prefer jumble the syntax into a single line:
var_export(array_merge(...array_values(array_intersect_key($color_ids, array_flip($select)))));
Although a foreach() may perform a few nanoseconds faster than functional programming, you are never going to notice on such small data sets. One benefit of this coding style is that you don't have to name any temporary variables to push qualifying data into. In other words you can feed this directly into a return statement inside of a function which I find to be very tidy.
Alternatively, if you don't mind generating a result variable, then iterated array_push() calls while spreading the matching nominated color_id value is pretty simple. This technique is different in that if $select contains a color that is not a key in $color_id, then php will bark at you!
Code: (Demo)
$result = [];
foreach ($select as $color) {
array_push($result, ...$color_ids[$color]);
}
var_export($result);
Both techniques offer the same result.
Suppose I have an array of indexes, A.
Suppose I have an array B, where every key is an array containing some indexes or number.
I would know which of the entries in B contain some index appearing in A.
For example (in php style):
A = [3,45,67,8]
B = [ 1 => [1,6,81],
2 => [5,67,3,4,5,66,6],
3 => [55,56,57,58],
4 => [45,80,81,82]
]
The entries of B which contain some value of A are 2 and 4.
So the function I would make should be:
function solution = filter(A,B) // solution = [2,4]
Now, with a brute loop, looping over entries of B, the complexity will be
O(nm), where n is #B and m is the size of longest row in B.
There are smarter solutions?
Edit #2:
By moving all values to be compared to key positions, php can more than double efficienct (by my demo's system time metric).
Furthermore, if you have duplicate values in your subsets, calling array_flip() will reduce the size by disallowing duplicate keys.
Code: (Demo)
$A = array_flip($A); // prepare for key comparisons
$result = [];
foreach ($B as $key => $haystack) {
if (array_intersect_key(array_flip($haystack), $A)) {
$result[] = $key;
}
}
var_export($result);
Edit:
Whenever you want to optimize array searching with php, it is often best to try to prepare your data in a way which allows php to leverage its strength with hash tables. https://codedmemes.com/lib/best-performance-array-intersection/
Consider this preparation...
Code: (Demo)
foreach ($B as $key => $haystack) {
foreach ($haystack as $hay) {
$C[$hay][] = $key;
}
}
var_export(array_keys(array_flip((array_merge(...array_intersect_key($C, array_flip($A)))))));
Output:
array (
0 => 1,
1 => 2,
2 => 4,
)
The nested foreach() loops generate a collection of subarrays which have unique values from B's subarrays as keys and $B's original keys as new subarray values.
array_intersect_key() checks the keys which php does much faster than checking values. (see first hyperlink article)
Then array_merge(...) flattens the subarrays into a single 1-dim array.
Finally array_flip() and array_keys() removes duplicates and re-indexes the results.
I don't know exactly how array_intersect() works its magic in terms of efficiency, but this is probably how I'd go about it:
Code: (Demo)
$A = [3,45,67,8];
$B = [ 1 => [1,6,8],
2 => [5,67,3,4,5,66,6],
3 => [55,56,57,58],
4 => [45,80,81,82]
];
$result = [];
foreach ($B as $key => $haystack) {
if (array_intersect($haystack, $A)) { // generate an array with co-existing values
$result[] = $key; // add key if array_intersect makes a non-empty array
}
}
var_export($result);
Output:
array (
0 => 1,
1 => 2,
2 => 4,
)
I suppose if there is a "downside" to using array_intersect() it would be that it will bother to make multiple matches, when only a single match per row is necessary. For this reason, array_search() or a breaking loop might have advantages.
Code: (Demo)
$result = [];
foreach ($B as $key => $haystack) {
foreach ($haystack as $hay) {
if (in_array($hay, $A)) {
$result[] = $key;
break;
}
}
}
var_export($result); // same result
I have a relatively large array of elements which I want to search for a string and replace any matches. I'm currently trying to do this using preg_replace and regular expressions:
preg_replace("/\d?\dIPT\.\w/", "IPT", $array);
I want to get all values which match either 00IPT.A or 0IPT.A (with 0 representing any numerical character and A representing any letter) and replace them with IPT. However, I'm getting array to string conversion notices. Is there any way to get preg_replace to accept an array data source? If not, is there any other way I could achieve this?
The documentation says that preg_replace should be able to accept array sources — this is the reason I'm asking.
The string or an array with strings to search and replace.
If subject is an array, then the search and replace is performed on every entry of subject, and the return value is an array as well.
The array is multidimensional if that helps (has multiple arrays under one main array).
preg_replace doesn't modify in place. To permanently modify $array, you simply need to assign the result of preg_replace to it:
$array = preg_replace("/\d{1,2}IPT\.\w/", "IPT", $array);
works for me.
$array = array('00IPT.A', '0IPT.A');
$array = preg_replace("/\d{1,2}IPT\.\w/", "IPT", $array);
var_dump($array);
// output: array(2) { [0]=> string(3) "IPT" [1]=> string(3) "IPT" }
Note: the \d{1,2} means one or two digits.
If you want to do this to a two-dimensional array, you need to loop through the first dimension:
$array = array( array('00IPT.A', 'notmatch'), array('neither', '0IPT.A') );
foreach ($array as &$row) {
$row = preg_replace("/\d{1,2}IPT\.\w/", "IPT", $row);
}
var_dump($array);
output:
array(2) {
[0]=> array(2) {
[0]=> string(3) "IPT"
[1]=> string(8) "notmatch"
}
[1]=> &array(2) {
[0]=> string(7) "neither"
[1]=> string(3) "IPT"
}
}
Note that you have to loop through each row by reference (&$row) otherwise the original array will not be modified.
Your value does not sit in the array as a simple element but as a subset right? Like so?
array (
array ('id' => 45, 'name' => 'peter', 'whatyouarelookingfor' => '5F'),
array ('id' => 87, 'name' => 'susan', 'whatyouarelookingfor' => '8C'),
array ('id' => 92, 'name' => 'frank', 'whatyouarelookingfor' => '9R')
)
if so:
<?php
foreach ($array as $key => $value) {
$array[$key]['whatyouarelookingfor'] =
preg_replace("/\d?\dIPT\.\w/", "IPT", $value['whatyouarelookingfor']);
}
Or if more elements have this, just go broader:
<?php
foreach ($array as $key => $value) {
$array[$key] =
preg_replace("/\d?\dIPT\.\w/", "IPT", $value);
}
your $array contains some further arrays. preg_replace works fine with arrays of strings, but not with arrays of arrays [of arrays...] of strings.
Can someone please explain to me whats the difference between these 2 functions:
array_diff_ukey
array_diff_uassoc
They both take keys into the compare function, and based on those keys decide if the array element should be returned or not. I've checked the php manual, but to me they both seem to be doing the same thing...
array_diff_ukey returns those elements of the first array whose keys compare different to all keys in the second array (the semantics of the comparison being user-defined). The values associated with those keys do not play a part.
array_diff_uassoc is a "more inclusive" version of the above that also checks values: if a key in the first array compares equal to a key in the second array but the values are different, that element is also included in the result. In this case, comparison of values is not user-defined, but works as in array_diff: for two values to compare equal, their string representation must be identical.
Example, adapted from the PHP docs:
function key_compare_func($key1, $key2)
{
if ($key1 == $key2)
return 0;
else if ($key1 > $key2)
return 1;
else
return -1;
}
$array1 = array('blue' => 1, 'red' => 2, 'green' => "3", 'purple' => 4);
$array2 = array('green' => 3, 'blue' => 6, 'yellow' => 7, 'cyan' => 8);
var_dump(array_diff_ukey($array1, $array2, 'key_compare_func'));
var_dump(array_diff_uassoc($array1, $array2, 'key_compare_func'));
See it in action.
Here, array_diff_ukey will return the "red" and "purple" elements from $array1 because these keys do not compare equal to any of the keys in $array2. However array_diff_uassoc will also return the "blue" element, because even though that key exists in both arrays the associated values are different.
Note that the "green" element is not included in either result, despite the fact that the associated value is a string in $array1 and an integer in $array2.
From the manual:
array_diff — Computes the difference of arrays
array_diff_key — array_diff_key — Computes the difference of arrays using keys for comparison
array_diff_assoc — Computes the difference of arrays with additional index check
This additional index check means that not only the value must be the same, but also the key must be the same. So the difference between array_diff_ukey and array_diff_uassoc is that the latter checks both keys and values, while the first only checks the keys.
The addition of the u after diff_ means that you must supply a custom callback function instead of the default built-in function.
Example based on the manual (Fiddle)
<?php
header("Content-Type: text/plain");
$array1 = array('blue' => 1, 'red' => 2, 'green' => 3, 'black' => 0, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan' => 8, 'black' => 0);
var_dump(array_diff($array1, $array2));
var_dump(array_diff_key($array1, $array2));
var_dump(array_diff_assoc($array1, $array2));
?>
Output
array(4) {
["blue"]=>
int(1)
["red"]=>
int(2)
["green"]=>
int(3)
["purple"]=>
int(4)
}
array(2) {
["red"]=>
int(2)
["purple"]=>
int(4)
}
array(4) {
["blue"]=>
int(1)
["red"]=>
int(2)
["green"]=>
int(3)
["purple"]=>
int(4)
}
Is there a fast way to return a key when you know its value in PHP?
For example, if you have:
$Numbers = (object) array ( "0" => 0, "1" => 1, "2" => 3, "3" => 7, "4" => 13 );
is there a way to return:
echo re(13); // Print 4
One way I could think of is to build a function specifically for this, but I was wondering if there is a better way.
There is array_search:
$key = array_search(13, (array) $Numbers);
See http://ua2.php.net/array_search
As several other people have mentioned, array_search does what you asked. But if you want an array of ALL the keys that contain the value instead of only the first, you can use array_keys.
print_r(array_keys($Numbers, 13)); // print Array ( [0] => 4 )
http://www.php.net/manual/en/function.array-keys.php
if you are certain that you have unique keys:
$flipped = array_flip($array);
$key = $flipped[$knownValue];
return $key;
Otherwise, use array_search:
return array_search($knownValue, $array);
The first approach may be better if you do a number of lookups, and have unique values. The second approach returns the first matching key in case of multiple values.
http://php.net/array_search
echo array_search($valToSearch, (array) $Numbers);
http://php.net/manual/en/function.array-search.php