I have an array with keys and values. Each value is an integer. I have an other array with the same keys. How can I subtract all of the values for the matching keys? Also there might be keys that do not occur in the second array but both arrays have the same length. If there is a key in array 2 that is not present in array 1 its value should be unchanged. If there is a key in the first array that is not in the second it should be thrown away. How do I do it? Is there any built-in function for this?
If I would write a script it would be some kind of for loop like this:
$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);
$ret = array();
foreach ($arr1 as $key => $value) {
$ret[$key] = $arr2[$key] - $arr1[$key];
}
print_r($ret);
/*
should be: array('a' => 1, 'b' => -2, 'c' => -5)
*/
I did not add the occasion here a key is in one array and not in the other.
You could avoid the foreach using array functions if you were so inclined.
The closure provided to array_mapdocs below will subtract each $arr1 value from each corresponding $arr2. Unfortunately array_map won't preserve your keys when using more than one input array, so we use array_combinedocs to merge the subtracted results back into an array with the original keys:
$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);
$subtracted = array_map(function ($x, $y) { return $y-$x; } , $arr1, $arr2);
$result = array_combine(array_keys($arr1), $subtracted);
var_dump($result);
UPDATE
I was interested in how the array functions approach compared to a simple foreach, so I benchmarked both using Xdebug. Here's the test code:
$arr1 = array('a' => 1, 'b' => 3, 'c' => 10);
$arr2 = array('a' => 2, 'b' => 1, 'c' => 5);
function arrayFunc($arr1, $arr2) {
$subtracted = array_map(function ($x, $y) { return $y-$x; } , $arr1, $arr2);
$result = array_combine(array_keys($arr1), $subtracted);
}
function foreachFunc($arr1, $arr2) {
$ret = array();
foreach ($arr1 as $key => $value) {
$ret[$key] = $arr2[$key] - $arr1[$key];
}
}
for ($i=0;$i<10000;$i++) { arrayFunc($arr1, $arr2); }
for ($i=0;$i<10000;$i++) { foreachFunc($arr1, $arr2); }
As it turns out, using the foreach loop is an order of magnitude faster than accomplishing the same task using array functions. As you can see from the below KCachegrind callee image, the array function method required nearly 80% of the processing time in the above code, while the foreach function required less than 5%.
The lesson here: sometimes the more semantic array functions (surprisingly?) can be inferior performance-wise to a good old fashioned loop in PHP. Of course, you should always choose the option that is more readable/semantic; micro-optimizations like this aren't justified if they make the code more difficult to understand six months down the road.
foreach ($arr2 as $key => $value) {
if(array_key_exists($key, $arr1) && array_key_exists($key, $arr2))
$ret[$key] = $arr2[$key] - $arr1[$key];
}
PHP does not offer vectorized mathematical operations. I would stick with your current approach of using a loop.
First, I would get the set of array keys for each array. (See the array_keys function). Then, intersect them. Now you will have the keys common to each array. (Take a look at the array_intersect function). Finally, iterate. It's a readable and simple approach.
Lastly, you could take a look at a library, such as Math_Vector: http://pear.php.net/package/Math_Vector
Related
I am searching for a built in php function that takes array of keys as input and returns me corresponding values.
for e.g. I have a following array
$arr = array("key1"=>100, "key2"=>200, "key3"=>300, 'key4'=>400);
and I need values for the keys key2 and key4 so I have another array("key2", "key4")
I need a function that takes this array and first array as inputs and provide me values in response. So response will be array(200, 400)
I think you are searching for array_intersect_key. Example:
array_intersect_key(array('a' => 1, 'b' => 3, 'c' => 5),
array_flip(array('a', 'c')));
Would return:
array('a' => 1, 'c' => 5);
You may use array('a' => '', 'c' => '') instead of array_flip(...) if you want to have a little simpler code.
Note the array keys are preserved. You should use array_values afterwards if you need a sequential array.
An alternative answer:
$keys = array("key2", "key4");
return array_map(function($x) use ($arr) { return $arr[$x]; }, $keys);
foreach($input_arr as $key) {
$output_arr[] = $mapping[$key];
}
This will result in $output_arr having the values corresponding to a list of keys in $input_arr, based on the key->value mapping in $mapping. If you want, you could wrap it in a function:
function get_values_for_keys($mapping, $keys) {
foreach($keys as $key) {
$output_arr[] = $mapping[$key];
}
return $output_arr;
}
Then you would just call it like so:
$a = array('a' => 1, 'b' => 2, 'c' => 3);
$values = get_values_for_keys($a, array('a', 'c'));
// $values is now array(1, 3)
I have an array like this:
array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2)
Now I want to filter that array by some condition and only keep the elements where the value is equal to 2 and delete all elements where the value is NOT 2.
So my expected result array would be:
array("a" => 2, "c" => 2, "f" => 2)
Note: I want to keep the keys from the original array.
How can I do that with PHP? Any built-in functions?
$fullArray = array('a'=>2,'b'=>4,'c'=>2,'d'=>5,'e'=>6,'f'=>2);
function filterArray($value){
return ($value == 2);
}
$filteredArray = array_filter($fullArray, 'filterArray');
foreach($filteredArray as $k => $v){
echo "$k = $v";
}
You somehow have to loop through your array and filter each element by your condition. This can be done with various methods.
Loops while / for / foreach method
Loop through your array with any loop you want, may it be while, for or foreach. Then simply check for your condition and either unset() the elements if they don't meet your condition or write the elements, which meet the condition, into a new array.
Looping
//while loop
while(list($key, $value) = each($array)){
//condition
}
//for loop
$keys = array_keys($array);
for($counter = 0, $length = count($array); $counter < $length; $counter++){
$key = $keys[$counter];
$value = $array[$key];
//condition
}
//foreach loop
foreach($array as $key => $value){
//condition
}
Condition
Just place your condition into the loop where the comment //condition is. The condition can just check for whatever you want and then you can either unset() the elements which don't meet your condition, and reindex the array with array_values() if you want, or write the elements in a new array which meet the condition.
//Pseudo code
//Use one of the two ways
if(condition){ //1. Condition fulfilled
$newArray[ ] = $value;
//↑ Put '$key' there, if you want to keep the original keys
//Result array is: $newArray
} else { //2. Condition NOT fulfilled
unset($array[$key]);
//Use array_values() after the loop if you want to reindex the array
//Result array is: $array
}
array_filter() method
Another method is to use the array_filter() built-in function. It generally works pretty much the same as the method with a simple loop.
You just need to return TRUE if you want to keep the element in the array and FALSE if you want to drop the element out of the result array.
//Anonymous function
$newArray = array_filter($array, function($value, $key){
//condition
}, ARRAY_FILTER_USE_BOTH);
//Function name passed as string
function filter($value, $key){
//condition
}
$newArray = array_filter($array, "filter", ARRAY_FILTER_USE_BOTH);
//'create_function()', NOT recommended
$newArray = array_filter($array, create_function('$value, $key', '/* condition */'), ARRAY_FILTER_USE_BOTH);
preg_grep() method
preg_grep() is similar to array_filter() just that it only uses regular expression to filter the array. So you might not be able to do everything with it, since you can only use a regular expression as filter and you can only filter by values or with some more code by keys.
Also note that you can pass the flag PREG_GREP_INVERT as third parameter to invert the results.
//Filter by values
$newArray = preg_grep("/regex/", $array);
Common conditions
There are many common conditions used to filter an array of which all can be applied to the value and or key of the array. I will just list a few of them here:
//Odd values
return $value & 1;
//Even values
return !($value & 1);
//NOT null values
return !is_null($value);
//NOT 0 values
return $value !== 0;
//Contain certain value values
return strpos($value, $needle) !== FALSE; //Use 'use($needle)' to get the var into scope
//Contain certain substring at position values
return substr($value, $position, $length) === $subString;
//NOT 'empty'(link) values
array_filter($array); //Leave out the callback parameter
You can iterate on the copies of the keys to be able to use unset() in the loop:
foreach (array_keys($array) as $key) {
if ($array[$key] != 2) {
unset($array[$key]);
}
}
The advantage of this method is memory efficiency if your array contains big values - they are not duplicated.
EDIT I just noticed, that you actually only need the keys that have a value of 2 (you already know the value):
$keys = array();
foreach ($array as $key => $value) {
if ($value == 2) {
$keys[] = $key;
}
}
This should work, but I'm not sure how efficient it is as you probably end up copying a lot of data.
$newArray = array_intersect_key(
$fullarray,
array_flip(array_keys($fullarray, 2))
);
This can be handled using a closure. The following answer is inspired by PHP The Right Way:
//This will create an anonymous function that will filter the items in the array by the value supplied
function cb_equal_to($val)
{
return function($item) use ($val) {
return $item == $val;
};
}
$input = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
// Use array_filter on a input with a selected filter function
$filtered_array = array_filter($input, cb_equal_to(2));
Contents of $filtered_array would now be
array ( ["a"] => 2 ["c"] => 2 ["f"] => 2 )
I think the snappiest, readable built-in function is: array_intersect()
Code: (Demo)
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
var_export(array_intersect($array, [2]));
Output:
array (
'a' => 2,
'c' => 2,
'f' => 2,
)
Just make sure you declare the 2nd parameter as an array because that is the value type expected.
Now there is nothing wrong with writing out a foreach loop, or using array_filter(), they just have a more verbose syntax.
array_intersect() is also very easy to extend (include additional "qualifying" values) by adding more values to the 2nd parameter array.
From PHP7.4, arrow function syntax is available. This affords more concise code and the ability to access global variables without use.
Code: (Demo)
$haystack = [
"a" => 2,
"b" => 4,
"c" => 2,
"d" => 5,
"e" => 6,
"f" => 2
];
$needle = 2;
var_export(
array_filter(
$haystack,
fn($v) => $v === $needle
)
);
I might do something like:
$newarray = array();
foreach ($jsonarray as $testelement){
if ($testelement == 2){$newarray[]=$testelement}
}
$result = count($newarray);
foreach ($aray as $key => $value) {
if (2 != $value) {
unset($array($key));
}
}
echo 'Items in array:' . count($array);
You can do something like:
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
$arrayFiltered = array_filter($array, function ($element) {
return $element == 2;
});
or:
$arrayFiltered = array_filter($array, fn($element) => $element == 2);
I have an array like this:
array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2)
Now I want to filter that array by some condition and only keep the elements where the value is equal to 2 and delete all elements where the value is NOT 2.
So my expected result array would be:
array("a" => 2, "c" => 2, "f" => 2)
Note: I want to keep the keys from the original array.
How can I do that with PHP? Any built-in functions?
$fullArray = array('a'=>2,'b'=>4,'c'=>2,'d'=>5,'e'=>6,'f'=>2);
function filterArray($value){
return ($value == 2);
}
$filteredArray = array_filter($fullArray, 'filterArray');
foreach($filteredArray as $k => $v){
echo "$k = $v";
}
You somehow have to loop through your array and filter each element by your condition. This can be done with various methods.
Loops while / for / foreach method
Loop through your array with any loop you want, may it be while, for or foreach. Then simply check for your condition and either unset() the elements if they don't meet your condition or write the elements, which meet the condition, into a new array.
Looping
//while loop
while(list($key, $value) = each($array)){
//condition
}
//for loop
$keys = array_keys($array);
for($counter = 0, $length = count($array); $counter < $length; $counter++){
$key = $keys[$counter];
$value = $array[$key];
//condition
}
//foreach loop
foreach($array as $key => $value){
//condition
}
Condition
Just place your condition into the loop where the comment //condition is. The condition can just check for whatever you want and then you can either unset() the elements which don't meet your condition, and reindex the array with array_values() if you want, or write the elements in a new array which meet the condition.
//Pseudo code
//Use one of the two ways
if(condition){ //1. Condition fulfilled
$newArray[ ] = $value;
//↑ Put '$key' there, if you want to keep the original keys
//Result array is: $newArray
} else { //2. Condition NOT fulfilled
unset($array[$key]);
//Use array_values() after the loop if you want to reindex the array
//Result array is: $array
}
array_filter() method
Another method is to use the array_filter() built-in function. It generally works pretty much the same as the method with a simple loop.
You just need to return TRUE if you want to keep the element in the array and FALSE if you want to drop the element out of the result array.
//Anonymous function
$newArray = array_filter($array, function($value, $key){
//condition
}, ARRAY_FILTER_USE_BOTH);
//Function name passed as string
function filter($value, $key){
//condition
}
$newArray = array_filter($array, "filter", ARRAY_FILTER_USE_BOTH);
//'create_function()', NOT recommended
$newArray = array_filter($array, create_function('$value, $key', '/* condition */'), ARRAY_FILTER_USE_BOTH);
preg_grep() method
preg_grep() is similar to array_filter() just that it only uses regular expression to filter the array. So you might not be able to do everything with it, since you can only use a regular expression as filter and you can only filter by values or with some more code by keys.
Also note that you can pass the flag PREG_GREP_INVERT as third parameter to invert the results.
//Filter by values
$newArray = preg_grep("/regex/", $array);
Common conditions
There are many common conditions used to filter an array of which all can be applied to the value and or key of the array. I will just list a few of them here:
//Odd values
return $value & 1;
//Even values
return !($value & 1);
//NOT null values
return !is_null($value);
//NOT 0 values
return $value !== 0;
//Contain certain value values
return strpos($value, $needle) !== FALSE; //Use 'use($needle)' to get the var into scope
//Contain certain substring at position values
return substr($value, $position, $length) === $subString;
//NOT 'empty'(link) values
array_filter($array); //Leave out the callback parameter
You can iterate on the copies of the keys to be able to use unset() in the loop:
foreach (array_keys($array) as $key) {
if ($array[$key] != 2) {
unset($array[$key]);
}
}
The advantage of this method is memory efficiency if your array contains big values - they are not duplicated.
EDIT I just noticed, that you actually only need the keys that have a value of 2 (you already know the value):
$keys = array();
foreach ($array as $key => $value) {
if ($value == 2) {
$keys[] = $key;
}
}
This should work, but I'm not sure how efficient it is as you probably end up copying a lot of data.
$newArray = array_intersect_key(
$fullarray,
array_flip(array_keys($fullarray, 2))
);
This can be handled using a closure. The following answer is inspired by PHP The Right Way:
//This will create an anonymous function that will filter the items in the array by the value supplied
function cb_equal_to($val)
{
return function($item) use ($val) {
return $item == $val;
};
}
$input = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
// Use array_filter on a input with a selected filter function
$filtered_array = array_filter($input, cb_equal_to(2));
Contents of $filtered_array would now be
array ( ["a"] => 2 ["c"] => 2 ["f"] => 2 )
I think the snappiest, readable built-in function is: array_intersect()
Code: (Demo)
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
var_export(array_intersect($array, [2]));
Output:
array (
'a' => 2,
'c' => 2,
'f' => 2,
)
Just make sure you declare the 2nd parameter as an array because that is the value type expected.
Now there is nothing wrong with writing out a foreach loop, or using array_filter(), they just have a more verbose syntax.
array_intersect() is also very easy to extend (include additional "qualifying" values) by adding more values to the 2nd parameter array.
From PHP7.4, arrow function syntax is available. This affords more concise code and the ability to access global variables without use.
Code: (Demo)
$haystack = [
"a" => 2,
"b" => 4,
"c" => 2,
"d" => 5,
"e" => 6,
"f" => 2
];
$needle = 2;
var_export(
array_filter(
$haystack,
fn($v) => $v === $needle
)
);
I might do something like:
$newarray = array();
foreach ($jsonarray as $testelement){
if ($testelement == 2){$newarray[]=$testelement}
}
$result = count($newarray);
foreach ($aray as $key => $value) {
if (2 != $value) {
unset($array($key));
}
}
echo 'Items in array:' . count($array);
You can do something like:
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
$arrayFiltered = array_filter($array, function ($element) {
return $element == 2;
});
or:
$arrayFiltered = array_filter($array, fn($element) => $element == 2);
I have an array like this:
array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2)
Now I want to filter that array by some condition and only keep the elements where the value is equal to 2 and delete all elements where the value is NOT 2.
So my expected result array would be:
array("a" => 2, "c" => 2, "f" => 2)
Note: I want to keep the keys from the original array.
How can I do that with PHP? Any built-in functions?
$fullArray = array('a'=>2,'b'=>4,'c'=>2,'d'=>5,'e'=>6,'f'=>2);
function filterArray($value){
return ($value == 2);
}
$filteredArray = array_filter($fullArray, 'filterArray');
foreach($filteredArray as $k => $v){
echo "$k = $v";
}
You somehow have to loop through your array and filter each element by your condition. This can be done with various methods.
Loops while / for / foreach method
Loop through your array with any loop you want, may it be while, for or foreach. Then simply check for your condition and either unset() the elements if they don't meet your condition or write the elements, which meet the condition, into a new array.
Looping
//while loop
while(list($key, $value) = each($array)){
//condition
}
//for loop
$keys = array_keys($array);
for($counter = 0, $length = count($array); $counter < $length; $counter++){
$key = $keys[$counter];
$value = $array[$key];
//condition
}
//foreach loop
foreach($array as $key => $value){
//condition
}
Condition
Just place your condition into the loop where the comment //condition is. The condition can just check for whatever you want and then you can either unset() the elements which don't meet your condition, and reindex the array with array_values() if you want, or write the elements in a new array which meet the condition.
//Pseudo code
//Use one of the two ways
if(condition){ //1. Condition fulfilled
$newArray[ ] = $value;
//↑ Put '$key' there, if you want to keep the original keys
//Result array is: $newArray
} else { //2. Condition NOT fulfilled
unset($array[$key]);
//Use array_values() after the loop if you want to reindex the array
//Result array is: $array
}
array_filter() method
Another method is to use the array_filter() built-in function. It generally works pretty much the same as the method with a simple loop.
You just need to return TRUE if you want to keep the element in the array and FALSE if you want to drop the element out of the result array.
//Anonymous function
$newArray = array_filter($array, function($value, $key){
//condition
}, ARRAY_FILTER_USE_BOTH);
//Function name passed as string
function filter($value, $key){
//condition
}
$newArray = array_filter($array, "filter", ARRAY_FILTER_USE_BOTH);
//'create_function()', NOT recommended
$newArray = array_filter($array, create_function('$value, $key', '/* condition */'), ARRAY_FILTER_USE_BOTH);
preg_grep() method
preg_grep() is similar to array_filter() just that it only uses regular expression to filter the array. So you might not be able to do everything with it, since you can only use a regular expression as filter and you can only filter by values or with some more code by keys.
Also note that you can pass the flag PREG_GREP_INVERT as third parameter to invert the results.
//Filter by values
$newArray = preg_grep("/regex/", $array);
Common conditions
There are many common conditions used to filter an array of which all can be applied to the value and or key of the array. I will just list a few of them here:
//Odd values
return $value & 1;
//Even values
return !($value & 1);
//NOT null values
return !is_null($value);
//NOT 0 values
return $value !== 0;
//Contain certain value values
return strpos($value, $needle) !== FALSE; //Use 'use($needle)' to get the var into scope
//Contain certain substring at position values
return substr($value, $position, $length) === $subString;
//NOT 'empty'(link) values
array_filter($array); //Leave out the callback parameter
You can iterate on the copies of the keys to be able to use unset() in the loop:
foreach (array_keys($array) as $key) {
if ($array[$key] != 2) {
unset($array[$key]);
}
}
The advantage of this method is memory efficiency if your array contains big values - they are not duplicated.
EDIT I just noticed, that you actually only need the keys that have a value of 2 (you already know the value):
$keys = array();
foreach ($array as $key => $value) {
if ($value == 2) {
$keys[] = $key;
}
}
This should work, but I'm not sure how efficient it is as you probably end up copying a lot of data.
$newArray = array_intersect_key(
$fullarray,
array_flip(array_keys($fullarray, 2))
);
This can be handled using a closure. The following answer is inspired by PHP The Right Way:
//This will create an anonymous function that will filter the items in the array by the value supplied
function cb_equal_to($val)
{
return function($item) use ($val) {
return $item == $val;
};
}
$input = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
// Use array_filter on a input with a selected filter function
$filtered_array = array_filter($input, cb_equal_to(2));
Contents of $filtered_array would now be
array ( ["a"] => 2 ["c"] => 2 ["f"] => 2 )
I think the snappiest, readable built-in function is: array_intersect()
Code: (Demo)
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
var_export(array_intersect($array, [2]));
Output:
array (
'a' => 2,
'c' => 2,
'f' => 2,
)
Just make sure you declare the 2nd parameter as an array because that is the value type expected.
Now there is nothing wrong with writing out a foreach loop, or using array_filter(), they just have a more verbose syntax.
array_intersect() is also very easy to extend (include additional "qualifying" values) by adding more values to the 2nd parameter array.
From PHP7.4, arrow function syntax is available. This affords more concise code and the ability to access global variables without use.
Code: (Demo)
$haystack = [
"a" => 2,
"b" => 4,
"c" => 2,
"d" => 5,
"e" => 6,
"f" => 2
];
$needle = 2;
var_export(
array_filter(
$haystack,
fn($v) => $v === $needle
)
);
I might do something like:
$newarray = array();
foreach ($jsonarray as $testelement){
if ($testelement == 2){$newarray[]=$testelement}
}
$result = count($newarray);
foreach ($aray as $key => $value) {
if (2 != $value) {
unset($array($key));
}
}
echo 'Items in array:' . count($array);
You can do something like:
$array = array("a" => 2, "b" => 4, "c" => 2, "d" => 5, "e" => 6, "f" => 2);
$arrayFiltered = array_filter($array, function ($element) {
return $element == 2;
});
or:
$arrayFiltered = array_filter($array, fn($element) => $element == 2);
I am searching for a built in php function that takes array of keys as input and returns me corresponding values.
for e.g. I have a following array
$arr = array("key1"=>100, "key2"=>200, "key3"=>300, 'key4'=>400);
and I need values for the keys key2 and key4 so I have another array("key2", "key4")
I need a function that takes this array and first array as inputs and provide me values in response. So response will be array(200, 400)
I think you are searching for array_intersect_key. Example:
array_intersect_key(array('a' => 1, 'b' => 3, 'c' => 5),
array_flip(array('a', 'c')));
Would return:
array('a' => 1, 'c' => 5);
You may use array('a' => '', 'c' => '') instead of array_flip(...) if you want to have a little simpler code.
Note the array keys are preserved. You should use array_values afterwards if you need a sequential array.
An alternative answer:
$keys = array("key2", "key4");
return array_map(function($x) use ($arr) { return $arr[$x]; }, $keys);
foreach($input_arr as $key) {
$output_arr[] = $mapping[$key];
}
This will result in $output_arr having the values corresponding to a list of keys in $input_arr, based on the key->value mapping in $mapping. If you want, you could wrap it in a function:
function get_values_for_keys($mapping, $keys) {
foreach($keys as $key) {
$output_arr[] = $mapping[$key];
}
return $output_arr;
}
Then you would just call it like so:
$a = array('a' => 1, 'b' => 2, 'c' => 3);
$values = get_values_for_keys($a, array('a', 'c'));
// $values is now array(1, 3)