Difference Between Array_Map, Array_Walk and Array_Filter

Difference between array_map, array_walk and array_filter

  • Changing Values:

    • array_map cannot change the values inside input array(s) while array_walk can; in particular, array_map never changes its arguments.
  • Array Keys Access:

    • array_map cannot operate with the array keys, array_walk can.
  • Return Value:

    • array_map returns a new array, array_walk only returns true. Hence, if you don't want to create an array as a result of traversing one array, you should use array_walk.
  • Iterating Multiple Arrays:

    • array_map also can receive an arbitrary number of arrays and it can iterate over them in parallel, while array_walk operates only on one.
  • Passing Arbitrary Data to Callback:

    • array_walk can receive an extra arbitrary parameter to pass to the callback. This mostly irrelevant since PHP 5.3 (when anonymous functions were introduced).
  • Length of Returned Array:

    • The resulting array of array_map has the same length as that of the largest input array; array_walk does not return an array but at the same time it cannot alter the number of elements of original array; array_filter picks only a subset of the elements of the array according to a filtering function. It does preserve the keys.

Example:

<pre>
<?php

$origarray1 = array(2.4, 2.6, 3.5);
$origarray2 = array(2.4, 2.6, 3.5);

print_r(array_map('floor', $origarray1)); // $origarray1 stays the same

// changes $origarray2
array_walk($origarray2, function (&$v, $k) { $v = floor($v); });
print_r($origarray2);

// this is a more proper use of array_walk
array_walk($origarray1, function ($v, $k) { echo "$k => $v", "\n"; });

// array_map accepts several arrays
print_r(
array_map(function ($a, $b) { return $a * $b; }, $origarray1, $origarray2)
);

// select only elements that are > 2.5
print_r(
array_filter($origarray1, function ($a) { return $a > 2.5; })
);

?>
</pre>

Result:

Array
(
[0] => 2
[1] => 2
[2] => 3
)
Array
(
[0] => 2
[1] => 2
[2] => 3
)
0 => 2.4
1 => 2.6
2 => 3.5
Array
(
[0] => 4.8
[1] => 5.2
[2] => 10.5
)
Array
(
[1] => 2.6
[2] => 3.5
)

Difference between array_filter() and array_map()?

All three, array_filter, array_map, and array_walk, use a callback function to loop through an array much in the same way foreach loops loop through an $array using $key => $value pairs.

For the duration of this post, I will be referring to the original array, passed to the above mentioned functions, as $array, the index, of the current item in the loop, as $key, and the value, of the current item in the loop, as $value.

array_filter is likened to MySQL's SELECT query which SELECTs records but doesn't modify them.

array_filter's callback is passed the $value of the current loop item and whatever the callback returns is treated as a boolean.

If true, the item is included in the results.

If false, the item is excluded from the results.

Thus you might do:

<pre><?php
$users=array('user1'=>array('logged_in'=>'Y'),'user2'=>array('logged_in'=>'N'),'user3'=>array('logged_in'=>'Y'),'user4'=>array('logged_in'=>'Y'),'user5'=>array('logged_in'=>'N'));
function signedIn($value)
{
if($value['logged_in']=='Y')return true;
return false;
}
$signedInUsers=array_filter($users,'signedIn');
print_r($signedInUsers);//Array ( [user1] => Array ( [logged_in] => Y ) [user3] => Array ( [logged_in] => Y ) [user4] => Array ( [logged_in] => Y ) )
?></pre>

array_map on the other hand accepts multiple arrays as arguments.
If one array is specified, the $value of the current item in the loop is sent to the callback.
If two or more arrays are used, all the arrays need to first be passed through array_values as mentioned in the documentation:

If the array argument contains string keys then the returned array
will contain string keys if and only if exactly one array is passed.
If more than one argument is passed then the returned array always has
integer keys

The first array is looped through and its value is passed to the callback as its first parameter, and if a second array is specified it will also be looped through and its value will be sent as the 2nd parameter to the callback and so-on and so-forth for each additional parameter.

If the length of the arrays don't match, the largest array is used, as mentioned in the documentation:

Usually when using two or more arrays, they should be of equal length
because the callback function is applied in parallel to the
corresponding elements. If the arrays are of unequal length, shorter
ones will be extended with empty elements to match the length of the
longest.

Each time the callback is called, the return value is collected.
The keys are preserved only when working with one array, and array_map returns the resulting array.
If working with two or more arrays, the keys are lost and instead a new array populated with the callback results is returned.
array_map only sends the callback the $value of the current item not its $key.
If you need the key as well, you can pass array_keys($array) as an additional argument then the callback will receive both the $key and $value.

However, when using multiple arrays, the original keys will be lost in much the same manner as array_values discards the keys.
If you need the keys to be preserved, you can use array_keys to grab the keys from the original array and array_values to grab the values from the result of array_map, or just use the result of array_map directly since it is already returning the values, then combine the two using array_combine.

Thus you might do:

<pre><?php
$array=array('apple'=>'a','orange'=>'o');
function fn($key,$value)
{
return $value.' is for '.$key;
}
$result=array_map('fn',array_keys($array),$array);
print_r($result);//Array ( [0] => a is for apple [1] => o is for orange )
print_r(array_combine(array_keys($array),$result));//Array ( [apple] => a is for apple [orange] => o is for orange )
?></pre>

array_walk is very similar to foreach($array as $key=>$value) in that the callback is sent both a key and a value. It also accepts an optional argument if you want to pass in a 3rd argument directly to the callback.

array_walk returns a boolean value indicating whether the loop completed successfully.

(I have yet to find a practical use for it)

Note that array_walk doesn't make use of the callback's return.
Since array_walk returns a boolean value, in order for array_walk to affect something,
you'll need to reference &$value so you have that which to modify or use a global array.
Alternatively, if you don't want to pollute the global scope, array_walk's optional 3rd argument can be used to pass in a reference to a variable with which to write to.

Thus you might do:

<pre><?php
$readArray=array(1=>'January',2=>'February',3=>'March',4=>'April',5=>'May',6=>'June',7=>'July',8=>'August',9=>'September',10=>'October',11=>'November',12=>'December');
$writeArray=array();
function fn($value,$key,&$writeArray)
{
$writeArray[$key]=substr($value,0,3);
}
array_walk($readArray,'fn',&$writeArray);
print_r($writeArray);//Array ( [1] => Jan [2] => Feb [3] => Mar [4] => Apr [5] => May [6] => Jun [7] => Jul [8] => Aug [9] => Sep [10] => Oct [11] => Nov [12] => Dec )
?></pre>

Why does this code use array_filter and array_map to filter an array of integers?

There would be no difference at all if you use the second one as a replacement of first one.

Why: This is due to behaviour of intval function.

intval Returns integer value of variable on success, or 0 on failure. Empty arrays return 0, non-empty arrays return 1.

Point to be noticed: 0 is considered as false, and any other non-zero integer value considered as true in PHP.

array_filter filters data based on return value of callable function which should be either true of false.

Now in your situation you're calling array_filter in two manners.

array_filter( array_map( 'intval', (array) $_POST['product_ids'] ) )

  • In this you're passing an array of integers to array_filter as array_map will loop over array and convert each value to corresponding integer by calling intval function.
  • Now as there is no parameter passed in array_filter so by default empty function will be used and only numeric but not zero(0) values remains.

array_filter( (array) $_POST['product_ids'], 'intval' )

  • In this you are calling array_filter but intval as callable function, which will convert each value to corresponding integer. Main catch is here, if corresponding value is 0 then it will be false, otherwise true, which is equivalent to empty function in this case.

Note: This doesn't apply to other functions and would not create same results. See this by comparing intval and is_string function.

// Input data
$entry = [
0 => 'foo',
1 => false,
2 => -1,
3 => null,
4 => '',
5 => '0',
6 => 0,
];

// comparison for intval function
print_r(array_filter( array_map( 'intval', $entry ) ));
print_r(array_filter( $entry, 'intval' ));

Output:
Array
(
[2] => -1
)
Array
(
[2] => -1
)

// but if you try another function like is_string
print_r(array_filter( array_map( 'is_string', $entry ) ));
print_r(array_filter( $entry, 'is_string' ));
Output:
Array
(
[0] => 1
[4] => 1
[5] => 1
)
Array
(
[0] => foo
[4] =>
[5] => 0
)

array_walk or array_map?

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

Why does the function signature differ between array_map and array_filter/array_reduce?

Does array_map take an array as the last parameter simply because you can feed as many arrays as you want (variadic)?

Yes; only the last parameter in a method signature can be variadic.

Does the ability to feed an arbitrary number of arrays through the callback function of array_map outweigh having more uniform function signatures?

Essentially, this is asking if array_map should accept multiple arrays. There are good use cases for allowing for calling array_map with multiple arrays; below is an example from the PHP array_map guide that I've slightly modified:

<?php
function showLanguages($n, $s, $g)
{
return("The number $n is called $s in Spanish and $g in German.");
}

$a = array(1, 2, 3, 4, 5);
$b = array("uno", "dos", "tres", "cuatro", "cinco");
$c = array("eins", "zwei", "drei", "vier", "funf");

$d = array_map("showLanguages", $a, $b, $c);
print_r($d);

What if array_map were changed to have a multidimensional array as the first argument? While it would technically make the function signatures more uniform, it would actually add some additional problems.

The underlying code would not only have to validate that the first argument is an array, it would have to validate that it's an array of arrays. That would make it essentially be a different kind of parameter than just an array, so it would still be a different method signature than the other array_* methods.

If you really wanted to have the callback as the last argument, you could use a modified function that removes the last element, move it to the first argument, then call array_map on that. You would lose all type-hinting, though, so it'd be harder to use.

/*
* Accepts a variable number of arrays as the first N arguments, takes a callback as the last argument
*/
function map()
{
$args = func_get_args();

$callback = array_pop($args);

array_unshift($args, $callback);

return call_user_func_array("array_map", $args);
}

Remove element from array using array_map

I think array_map is not designed for your needs, because it's apply a callback for each element of your array. But array_filter does :

$array = array_filter($array, function($e) {
return is_numeric($e);
});

Or even shorter :

$array = array_filter($array, 'is_numeric');

How to pass standard php functions to array_map and array_filter?

You need to pass the function (user-defined OR builtin) name as a string in the parameter of array_map function.

Do the following:

$result = array_map('boolval', $elements);

array_walk vs array_map vs foreach

array_walk doesn't look at what result function gives. Instead it passes callback a reference to item value. So your code for it to work needs to be

function walk_trim(&$value) {
$value = trim($value);
}

foreach doesn't store changed values itself either. Change it to

foreach ($input3 as &$in) {
$in = trim($in);
}

Read more about references.

Display array result in html table using array_walk or array_map

You are confusing where you put the PHP code.

Try with this:

<?php
function myfunction($value, $key) {
echo '<tr><td>'.$value.'</td><td>Edit</td></tr>';
}

$a = array("a" => "user1", "b" => "user2", "c" => "user3");

$users = $this->db->get('user')->result();
echo '<table><tr><th>Name</th><th>Edit</th></tr><tbody>';
array_walk($a, "myfunction");
echo '</tbody></table>';
?>


Related Topics



Leave a reply



Submit