dismiss Step into the future! Click here to switch to the beta php.net site
downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | conferences | my php.net

search for in the

array_replace_recursive> <array_rand
[edit] Last updated: Fri, 27 Sep 2013

view this page in

array_reduce

(PHP 4 >= 4.0.5, PHP 5)

array_reduceIteratively reduce the array to a single value using a callback function

Description

mixed array_reduce ( array $array , callable $callback [, mixed $initial = NULL ] )

array_reduce() applies iteratively the callback function to the elements of the array, so as to reduce the array to a single value.

Parameters

array

The input array.

callback

The callback function.

mixed callback ( mixed &$result , mixed $item )
initial

If the optional initial is available, it will be used at the beginning of the process, or as a final result in case the array is empty.

Return Values

Returns the resulting value.

If the array is empty and initial is not passed, array_reduce() returns NULL.

Changelog

Version Description
5.3.0 Changed initial to allow mixed, previously integer.

Examples

Example #1 array_reduce() example

<?php
function rsum($v$w)
{
    
$v += $w;
    return 
$v;
}

function 
rmul($v$w)
{
    
$v *= $w;
    return 
$v;
}

$a = array(12345);
$x = array();
$b array_reduce($a"rsum");
$c array_reduce($a"rmul"10);
$d array_reduce($x"rsum""No data to reduce");
?>

This will result in $b containing 15, $c containing 1200 (= 10*1*2*3*4*5), and $d containing No data to reduce.

See Also



array_replace_recursive> <array_rand
[edit] Last updated: Fri, 27 Sep 2013
 
add a note add a note User Contributed Notes array_reduce - [18 notes]
up
5
Hayley Watson
5 years ago
To make it clearer about what the two parameters of the callback are for, and what "reduce to a single value" actually means (using associative and commutative operators as examples may obscure this).

The first parameter to the callback is an accumulator where the result-in-progress is effectively assembled. If you supply an $initial value the accumulator starts out with that value, otherwise it starts out null.
The second parameter is where each value of the array is passed during each step of the reduction.
The return value of the callback becomes the new value of the accumulator. When the array is exhausted, array_reduce() returns accumulated value.

If you carried out the reduction by hand, you'd get something like the following lines, every one of which therefore producing the same result:
<?php
array_reduce
(array(1,2,3,4), 'f',         99             );
array_reduce(array(2,3,4),   'f',       f(99,1)          );
array_reduce(array(3,4),     'f',     f(f(99,1),2)       );
array_reduce(array(4),       'f',   f(f(f(99,1),2),3)    );
array_reduce(array(),        'f', f(f(f(f(99,1),2),3),4) );
f(f(f(f(99,1),2),3),4)
?>

If you made function f($v,$w){return "f($v,$w)";} the last line would be the literal result.

A PHP implementation might therefore look something like this (less details like error checking and so on):
<?php
function array_reduce($array, $callback, $initial=null)
{
   
$acc = $initial;
    foreach(
$array as $a)
       
$acc = $callback($acc, $a);
    return
$acc;
}
?>
up
3
Seanj.jcink.com
7 years ago
The code posted below by bishop to count the characters of an array is simply... erm... well useless to me...

$array=Array("abc","de","f");
strlen(implode("",$array)); //6

works; and is much smaller. Probably much faster too.
up
2
ruslan dot zavackiy at gmail dot com
1 year ago
If you want something elegant in your code, when dealing with reducing array, just unshift first element, and use it as initial, because if you do not do so, you will + first element with first element:

<?php
$arr
= array(
    array(
'min' => 1.5456, 'max' => 2.28548, 'volume' => 23.152),
    array(
'min' => 1.5457, 'max' => 2.28549, 'volume' => 23.152),
    array(
'min' => 1.5458, 'max' => 2.28550, 'volume' => 23.152),
    array(
'min' => 1.5459, 'max' => 2.28551, 'volume' => 23.152),
    array(
'min' => 1.5460, 'max' => 2.28552, 'volume' => 23.152),
);

$initial = array_shift($arr);

$t = array_reduce($arr, function($result, $item) {
   
$result['min'] = min($result['min'], $item['min']);
   
$result['max'] = max($result['max'], $item['max']);
   
$result['volume'] += $item['volume'];

    return
$result;
},
$initial);
?>
up
3
php at keith tyler dot com
3 years ago
It seems that $initial is a required value; if you do not provide $initial, the first value used in the iteration is NULL.

Perhaps this is not a problem for callback functions that treat NULL as an identity (e.g. addition), but is a problem for cases when NULL is not identity (such as boolean context).

Compare:

<?php
function andFunc($a,$b) {
  return
$a&&$b;
}
$foo=Array(true,true,true);
var_dump(array_reduce($foo,"andFunc"));
?>

returns false! One would expect that it would return true because true&&true&&true == true!

Adding diagnostic output to andFunc() shows that the first call to andFunc is with the arguments (NULL,true). This resolves to false (as (bool)null == false) and thereby corrupts the whole reduction.

So in this case I have to set $initial=true so that the first call to andFunc() will be (true,true). Now, if I were doing, say, orFunc(), I would have to set $initial=false. Beware.

Note that the "rmul" case in the example sneakily hides this defect! They use an $initial of 10 to get 10*1*2*3*4*5=12000. So you would assume that without an initial, you would get 1200/10 = 120 = 1*2*3*4*5. Nope! You get big fat zero, because int(null)==0, and 0*1*2*3*4*5 = 0!

I don't honestly see why array_reduce starts with a null argument. The first call to the callback should be with arguments ($initial[0],$initial[1]) [or whatever the first two array entries are], not (null,$initial[0]). That's what one would expect from the description.

Incidentally this also means that under the current implementation you will incur count($input) number of calls to the callback, not count($input)-1 as you might expect.
up
2
php dot net at cuntbubble dot com
11 years ago
There is an error/misleading item in the documentation

[, int initial]

int is not constrained to an integer, it can be any data type (although I've not tested ALL data types)

and $v is the cumulative part, the current value of the reduction.

and I'll take the liberty to add another example, as used in my code

<?php
function reduceToTable($html, $p) {
   
$html .= "<TR><TD><a href=\"$p.html\">$p</a></td>\n";
    return
$html;
}

$list = Array("page1", "page2", "page3");

$tab = array_reduce($list, "reduceToTable", "<table>\n");
echo
$tab . "</table>\n";
?>

hmm, getting stuff on one line sure is tricky, it get's wordwrapped on the char count in html so &gt; counts as 4 chars not one so by the time you've counted "< you've used up 8 chars
If it get's through moderation could someone please make it look ok :)
up
1
Janez R.
6 years ago
--REPOST, fixed some typos, please replace previous note--
In PHP ver. 4.3.1 the initial value parameter allowed for string type also. In PHP ver. 5.1.6 this param is now converted to int and callback function will receive number 0 when initial param is an empty string.

<?php
function arc ($reduced, $item)
{
 
$reduced = $item.$reduced;
  return
$reduced;
}

array_reduce( array(a,b,c), "arc", "" );
?>

Output in PHP 4.3.1: cba
Output in PHP 5.1.6: cba0

Possible solution:
<?php
function arc ($reduced, $item)
{
  if (
$reduced === 0$reduced = "";
 
$reduced = $item.$reduced;
  return
$reduced;
}
?>
up
1
yuki [dot] kodama [at] gmail [dot] com
6 years ago
This code will reduce array deeply.

<?php
function print_s($s) {
    return
is_null($s) ? "NULL" : (is_array($s) ? "Array" : ($s ? "TRUE" : "FALSE"));
}
function
r_and_dp($a, $b) {
    echo
"phase1:" . print_s($a) . "," . print_s($b) . "<br>\n";
    if(
is_array($a)) {
       
$a = array_reduce($a, "r_and_dp");
    }
    if(
is_array($b)) {
       
$b = array_reduce($b, "r_and_dp");
    }
    echo
"phase2:" . print_s($a) . "," . print_s($b) . "<br>\n";
   
$a = is_null($a) ? TRUE : $a;
   
$b = is_null($b) ? TRUE : $b;
    echo
"phase3:" . print_s($a) . "," . print_s($b) . "<br>\n";
    return
$a && $b;
}
$bools = array(TRUE, array(FALSE, TRUE), TRUE);
echo
print_s(array_reduce($bools, "r_and_dp")) . "<br>\n";

// result: FALSE
?>

When using boolean, you have to carefully set an "initial" argument.

<?php
function r_or_dp($a, $b) {
    if(
is_array($a)) {
       
$a = array_reduce($a, "r_or_dp");
    }
    if(
is_array($b)) {
       
$b = array_reduce($b, "r_or_dp");
    }
    return (
is_null($a) ? FALSE : $a) || (is_null($b) ? FALSE : $b);
}
?>
up
1
marcel dot oehler at kubusmedia dot com
7 years ago
I've just experienced some really strange behaviour of array_reduce in PHP 5.0.4:

$result = array( 0, 17, 0, 0, 33, 0, 0, 0, 0, 50);
$total = array_reduce( $result, "sumCalc", 0);

function sumCalc( $a, $b){
    return $a + $b;
}

and $total equals to 83!

I know, this could be done easier, but it should work nevertheless. Has anybody experienced something similar? I will avoid using array_reduce in the future...
up
0
kon
9 months ago
Walking down related object's properties using array_reduce:

<?php
  $a
=new stdClass;
 
$a->b=new stdClass;
 
$a->b->c="Hello World!\n";

 
$reductionPath=array("b","c");

 
print_r(
   
array_reduce(
     
$reductionPath,
      function(
$result, $item){
        return
$result->$item;
      },
     
$a
   
)
  );
?>
up
0
bdechka at yahoo dot ca
6 years ago
The above code works better this way.

<?php
function reduceToTable($html, $p) {
  
$html .= "<TR><TD><a href=\"$p.html\">$p</a></td></tr>\n";
   return
$html;
}

$list = Array("page1", "page2", "page3");

$tab = array_reduce($list, "reduceToTable");
echo
"<table>".$tab . "</table>\n";
?>
up
0
Hayley Watson
3 years ago
The note by Hrobky immediately below applies only to PHP versions prior to 5.3.0; as noted in the function's version history, $initial is now a "mixed" parameter.

What a difference a year makes :)
up
0
Hrobky
4 years ago
The initial value have to be int. So it is impossible to implement non-recursive flatten like this:

<?php
  $arr
= array(array(1), array(2), array(3));
 
$result = array_reduce($arr, 'array_merge', array());
 
// expected: $result == array (1, 2, 3)
?>

I get: Warning: array_merge() : Argument #1 is not an array.

If $initial parameter is not an int, array_reduce passes 0 (zero) to the callback function. Hayley Watson's note suggests a solution:

<?php
  $acc
= array();
  foreach(
$arr as $a)
   
$acc = array_merge($acc, $a);
 
// now: $acc == array (1, 2, 3)
?>
up
-1
tonicpeddler at aol dot com
10 years ago
in response to php dot net at cuntbubble dot com

actually when you pass a value to a function that accepts a specific data type, php automatically evaluates that value as the data type expected
up
-2
bishop
9 years ago
Count the total number of characters in an array of strings:

<?php
$lines
= array ('abc', 'd', 'ef');
$totalChars = array_reduce($lines, create_function('$v,$w','return $v + strlen($w);'), 0);
// $totalChars === 6
?>
up
-4
hans+php at pleasedontspamme dot hansdude dot com
1 year ago
This function is named fold in functional programming languages such as lisp, ocaml, haskell, and erlang. Python just calls it reduce.
up
-5
ildar [DASH] sh [AT] mail [DOT] ru
7 years ago
in rare cases when an array is a set of numeric values and result is one of sum or product of numbers the next examples may be useful

<?php

// sum of array items
echo eval('return ' . implode('+', $nums) . ';');

// product of array items
echo eval('return ' . implode('*', $nums) . ';');

?>

the reason of these codes is omitting of single used per script of callbacks
up
-2
david dot tulloh at infaze dot com dot au
8 years ago
The code supplied by cuntbubble is unfortunately incorrect.

Running it I got the output:
0<TR><TD><a href="page1.html">page1</a></td>
<TR><TD><a href="page2.html">page2</a></td>
<TR><TD><a href="page3.html">page3</a></td>
</table>

So php, not finding an integer, used int(0) to start the process.  I've tested to confirm this.
up
-3
aercolino at yahoo dot com
3 years ago
Thanks to php at keith tyler dot com, knowing that "if you do not provide $initial, the first value used in the iteration is NULL", we can write callbacks that test for is_null() and take any necessary step.

Example:

<?php
function andFunc($a, $b) {
  return (
is_null($a) ? true : $a) && $b;
}
$foo = array(true, true, true);
var_dump(array_reduce($foo, "andFunc"));
?>

It returns bool(true), as expected.

 
show source | credits | sitemap | contact | advertising | mirror sites