I'm currently using array_map to apply callbacks to elements of an array. But I want to be able to pass an argument to the callback function like array_walk does.
I suppose I could just use array_walk, but I need the return value to be an array like if you use array_map, not TRUE or FALSE.
So is it possible to use array_map and pass an argument to the callback function? Or perhaps make the array_walk return an array instead of boolean?
You don't need it to return an array.
Instead of:
$newArray = array_function_you_are_looking_for($oldArray, $funcName);
It's:
$newArray = $oldArray;
array_walk($newArray, $funcName);
If you want return value is an array, just use array_map. To add additional parameters to array_map use "use", ex:
array_map(function($v) use ($tmp) { return $v * $tmp; }, $array);
or
array_map(function($v) use ($a, $b) { return $a * $b; }, $array);
Depending on what kind of arguments you need to pass, you could create a wrapped function:
$arr = array(2, 4, 6, 8);
function mapper($val, $constant) {
return $val * $constant;
}
$constant = 3;
function wrapper($val) {
return mapper($val, $GLOBALS['constant']);
}
$arr = array_map('wrapper', $arr);
This actually seems too simple to be true. I suspect we'll need more context to really be able to help.
To expand a bit on Hieu's great answer, you can also use the $key => $value pairs of the original array. Here's an example with some code borrowed from comment section http://php.net/manual/en/function.array-map.php
The following will use 'use' and include an additional parameter which is a new array.
Below code will grab "b_value" and "d_value" and put into a new array $new_arr
(useless example to show a point)
// original array
$arr = ("a" => "b_value",
"c" => "d_value");
// new array
$new_arr = array();
array_map(function($k,$v) use (&$new_arr) { $new_arr[] = $v;}, array_keys($arr), $arr);
^ $k is key and $v is value
print_r of $new_arr is
Array
(
[0] => b_value
[1] => d_value
)
Related
I have such code
<?php
$array =
[
['key_name' => 'Amazon Inc.', 'key_code' => '102923'],
['key_name' => 'Google inc, co io', 'key_code' =>'283923'],
['key_name' => 'IMSFT dcs', 'key_code' => '3384823'],
['key_name' => 'MSFTSurfshark io', 'key_code' =>'4473873']
];
$search_text = 'mSfT';
$lowText = strtolower($search_text); // to lower
$lowArr = array_walk_recursive($array, function (&$v) {$v = mb_strtolower(trim($v));}); // need convert to lower case whole array
print_r($lowArr); // here is empty
$r = array_filter($lowArr, function($el) use ($lowText) {return ( strpos($el['key_name'], $lowText) !== false );
});
$keys = array_keys($r); // all keys founded
print_r( $r[$keys[0]]['key_code']); //return only first match
?>
When i want convert array to lower case
$lowArr = array_walk_recursive($array, function ($v) {$v = mb_strtolower(trim($v));});
then script return nothing using https://www.w3schools.com/php/phptryit.asp?filename=tryphp_intro
Goals is to find arrays elemnt by it key_name and return this element key_code
Why this happens?
If i use $array = array_column($array, 'key_name', 'key_code'); how should look like php syntax for same things?
Note this note in the manual.
If callback needs to be working with the actual values of the array, specify the first parameter of callback as a reference. Then, any changes made to those elements will be made in the original array itself.
So you need declare the parameter as a reference in order to make changes to the original array.
function (&$v) {$v = mb_strtolower(trim($v));}
PHP is easy language to learn but one thing that's triggering me is PHP's positions of function parameters.
Example #1
array_walk($array, $callback);
array_map($callback, $array);
Example #2
array_push($array, $mixed);
array_search($mixed, $array);
It just don't make any sense. Does PHP developers make this intentionally?
It's all to do with what they do with an array. array_walk modifies the array by reference whilst array_map returns a new array.
Again, array_push modifies the array by reference and array_search returns a value from the array.
Where the array comes first in the arguments; will tend to mean the array will be modified by the function. It's very useful as a developer to know which functions are likely to modify the array being passed in.
Example:
<?php
$myArray = [1,2,3];
array_push($myArray,4);
var_dump($myArray); // array(1,2,3,4);
$myArray = [1,2,3];
$result = array_map(function ($val) { return $val * 2; }, $myArray);
var_dump($myArray); // array(1,2,3);
var_dump($result); // array(2,4,6);
I was wondering is it possible to convert the following array:
Array (
"2016-03-03 19:17:59",
"2016-03-03 19:20:54",
"2016-05-03 19:12:37"
)
Into this:
Array (
"2016-03-03",
"2016-03-03",
"2016-05-03"
)
Without creating any loops?
There's no explicit loops, if you can use array_map, although internally it loops:
function format_date($val) {
$v = explode(" ", $val);
return $v[0];
}
$arr = array_map("format_date", $arr);
From the PHP Manual:
array_map() returns an array containing all the elements of array1 after applying the callback function to each one. The number of parameters that the callback function accepts should match the number of arrays passed to the array_map().
Also, when you are dealing with Dates, the right way to do is as follows:
return date("Y-m-d", strtotime($val));
The simple way, using loops is to use a foreach():
foreach($arr as $key => $date)
$arr[$key] = date("Y-m-d", strtotime($date));
This is the most simplest looping way I can think of considering the index to be anything.
Input:
<?php
$arr = array(
"2016-03-03 19:17:59",
"2016-03-03 19:20:54",
"2016-05-03 19:12:37"
);
function format_date($val) {
$v = explode(" ", $val);
return $v[0];
}
$arr = array_map("format_date", $arr);
print_r($arr);
Output
Array
(
[0] => 2016-03-03
[1] => 2016-03-03
[2] => 2016-05-03
)
Demo: http://ideone.com/r9AyYV
Yes, use map:
function first10($s) {
return substr($s, 0, 10);
}
$result = array_map("first10", $yourArray);
WARNING: this is a good solution only if you are sure that the date format does not change, in other words the first 10 characters must contain the date.
Praveen Kumar's answer is probably the better solution but there is a way to do with what wouldn't really been seen as a loop. instead you use recursion
function explodeNoLoop($array,$delim,$index=0)
{
$returnArr = array();
if(isset($array[$index]))
{
$expldoed = explode($delim,$array[$index]);
array_push($returnArr,$expldoed[0]);
}
if(isset($array[$index+1]))
{
$returnArr = array_merge($returnArr,explodeNoLoop($array,$delim,$index+1));
}
return $returnArr;
}
$myArr = array (
"2016-03-03 19:17:59",
"2016-03-03 19:20:54",
"2016-05-03 19:12:37"
);
var_dump(explodeNoLoop($myArr," "));
example
How this code works is that with the function we explode the array at the index provided by the function parameter and add this to our returning array. Then we check if there is a value set at the next index which is +1 of the index we passed into the function. If it exists then we call the function again with the new index with the same array and delimiter. We then merge the results of this with our returner array and then return that.
However, with this one should be careful of nest level errors where you excursively call a function too many times, like looking into the reflection of a mirror in a mirror.
I have an associative PHP array and I would like to generate a list of keys that pass a certain test. For example
$myArray = ('28'=>0.01,'51'=>-0.1,'48'=>0.4,'53'=>-0.3);
And I'd like to filter the keys in the same way I can simply filter the values. So if I filter the values on "return the elements that are bigger than 0.2" would be
print_r(array_filter($myArray,"biggerThanFilter");
with
function biggerThanFilter($v){
return $v>0.2;
}
But how would I apply a filter to the keys which say the "keyValueIsBiggerThan50"
i.e something like this
print_r(array_KEY_filter($myArray,"keyValueIsBiggerThan50");
function keyValueIsBiggerThan50($key){
return $key*1>50;
}
I would loop through the array_keys and unset, personally:
function array_filter_keys($array, callable $fn)
foreach (array_keys($array) as $key) {
if (!$fn($key)) unset($array[$key])
}
return $array;
}
$filtered_array = array_filter_keys($array, function($key) { return $key > 50 });
This assumes PHP >= 5.4
function keyValueIsBiggerThan50 ($myArray) {
$newArray = array();
foreach($myArray as $key => $value){
if($key * 1 > 50){
$newArray[$key] = $value
}
}
return $newArray;
}
to be used like
print_r(keyValueIsBiggerThan50 ($myArray));
Are you looking for this specific case, or a generic?
For PHP 5.6+ my answer to a similar question also applies to this one: use ARRAY_FILTER_USE_KEY
<?php
$myArray = ['28' => 0.01, '51' => -0.1, '48' => 0.4, '53' => -0.3];
$filtered = array_filter(
$myArray,
function ($key) {
return $key > 50;
},
ARRAY_FILTER_USE_KEY
);
?>
For PHP < 5.6, array_diff_ukey performs a custom comparison of two arrays by key and appears to do a full N x M comparison so you can filter a single array by using a dummy as the second array.
Using PHP 5.5.9, I used the following to remove the numeric key elements from an array:
$res = array_diff_ukey($res, array(0), function ($a,$b){ return is_string($a); });
Lets assume we have two PHP-Arrays:
$some_array = array('a','b','c','d','e','f');
$another_array = array(101,102,103,104,105,106);
In PHP, there are already some Array-Functions that allow the construction of an Associative Array (AKA hash), e,g,;
$hash = array_combine(
$some_array,
$another_array
);
And here it comes. What should I do if I want to create a hash in a more functional style, if I want to compute key and value on the fly and build the hash through a map-operation, like (not working):
# wishful thinking
$hash = array_map(
function($a, $b){ return ($a => $b); },
$some_array,
$another_array
);
The problem here seems to be the expectation, the line
...
function($a, $b){ return ($a => $b); }
...
would indeed return an key value/pair of a hash - which it doesn't.
Q: How can I return a key/value pair from a function - which can be used to build up an associative array?
Addendum
To make clear what I really was looking for, I'll provide a perl example of hash generation:
...
# we have one array of characters (on which our hash generation is based)
my #array = qw{ a b c d e f };
# now *generate* a hash with array contents as keys and
# ascii numbers as values in a *single operation *
# (in Perl, the $_ variable represents the actual array element)
my %hash = map +($_ => ord $_), #array;
...
Result (%hash):
a => 97
b => 98
c => 99
d => 100
e => 101
f => 102
From the responses, I'd now think this is impossible in PHP. Thanks to all respondends.
EDIT: It's not entirely clear whether you're having a problem merely with returning multiple variables from a function, or whether you're having problems storing a function in an array. Your post gives the impression that storing the function in the array works, so I'll tackle the return-multiple-variables problem.
There is no way to return a single instance of a key/value pair in PHP. You have to have them in an array... but remember that in PHP, an array and hashmap are exactly the same thing. It's weird (and controversial), but that means it's perfectly legitimate to return an array/hashmap with the multiple values you wish to return.
There are only two sane ways that I know (from 10+ years of PHP experience) to get more than one variable out of a function. One is the good'ol fashion way of making the input variable changeable.
function vacuumPackSandwitch(&$a, &$b) {
$a = 505;
$b = 707;
}
This will change both $a and $b as opposed to changing copies of them like usual. For example:
$a = 1;
$b = 2;
vacuumPackSandwitch($a, $b);
print $a.' '.$b;
This will return "505 707", not "1 2" like normally. You might have to do:
vacuumPackSandwitch(&$a, &$b);
But if that's the case, the PHP compiler will duly let you know.
The other way is to return an array, which I suppose is the clearer and preferred way.
function ($a, $b) {
return array($a, $b);
}
You can grab both variables at the same time by doing:
list($c, $d) = vacuumPackSandwitch($a, $b);
Hope it helps!
In PHP arrays can be associative too! An int-indexed array is just an associative array with 0 => element0 and so on. Thus, you can accomplish what you are looking for like this:
$somearray = array('name' => 'test', 'pass' => '***', 'group' => 'admin');
function myfunc($a, $b) { return array($a => $b); }
if($somearray['name'] == 'test') { echo 'it works!'; }
// Let's add more data with the function now
$somearray += myfunc('location', 'internet');
//Test the result
if($somearray['location'] == 'internet') { echo 'it works again!'; }
It is really very simple. Hope this helps.
I know that this is an old question, but google still likes it for a search I recently made, so I'll post my findings. There are two ways to do this that come close to what you're attempting, both relying on the same general idea.
Idea 1:
Instead of returning a key => value pair, we return an array with only one element, 'key => value', for each sequential element of the original arrays. Then, we reduce these arrays, merging at every step.
$array = array_map(
function($a, $b){
return array($a => $b);
},
$arr1,
$arr2
);
$array = array_reduce(
$array,
function($carry, $element){
$carry = array_merge($carry, $element);
return $carry;
},
array()
);
OR
Idea 2:
Similar to idea one, but we do the key => value assignment in array_reduce. We pass NULL to array_map, which creates an array of arrays (http://php.net/manual/en/function.array-map.php)
$array = array_map(NULL, $a, $b);
$array = array_reduce(
$array,
function($carry, $element){
$carry[$element[0]] = $element[1];
return $carry;
},
array()
);
Personally, I find Idea 2 to be a lot more elegant than Idea 1, though it requires knowing that passing NULL as the function to array_map creates an array of arrays and is therefore somewhat un-intuitive. I just think of it as a precursor to array_reduce, where all the business happens.
Idea 3:
$carry = array();
$uselessArray = array_map(
function($a, $b) use ($carry){
$carry[$a] = $b;
},
$a,
$b
);
Idea 3 is an alternative to Idea 2, but I think it's hackier than Idea 2. We have to use 'use' to jump out of the function's scope, which is pretty ugly and probably contrary to the functional style OP was seeking.
Lets just streamline Idea 2 a little and see how that looks:
Idea 2(b):
$array = array_reduce(
array_map(NULL, $a, $b),
function($carry, $element){
$carry[$element[0]] = $element[1];
return $carry;
},
array()
);
Yeah, that's nice.