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)
?>
array_reduce
(PHP 4 >= 4.0.5, PHP 5)
array_reduce — コールバック関数を用いて配列を普通の値に変更することにより、配列を再帰的に減らす
説明
array_reduce() は、配列 input の各要素に function 関数を繰り返し適用し、 配列を一つの値に減らします。
パラメータ
- input
-
入力の配列。
- function
-
コールバック関数。
- initial
-
オプションの intial が利用可能な場合、処理の最初で使用されたり、 配列が空の場合の最終結果として使用されます。
返り値
結果の値を返します。
配列が空で initial が渡されなかった場合は、 array_reduce() は NULL を返します。
例
例1 array_reduce() の例
<?php
function rsum($v, $w)
{
$v += $w;
return $v;
}
function rmul($v, $w)
{
$v *= $w;
return $v;
}
$a = array(1, 2, 3, 4, 5);
$x = array();
$b = array_reduce($a, "rsum");
$c = array_reduce($a, "rmul", 10);
$d = array_reduce($x, "rsum", 1);
?>
これにより、$b の値は 15 となり、$c の値は 1200 (= 10*1*2*3*4*5)、そして $d の値は 1 となります。
参考
- array_filter() - コールバック関数を使用して、配列の要素をフィルタリングする
- array_map() - 指定した配列の要素にコールバック関数を適用する
- array_unique() - 配列から重複した値を削除する
- array_count_values() - 配列の値の数を数える
array_reduce
Hrobky
02-Apr-2009 07:34
02-Apr-2009 07:34
Hayley Watson
24-Oct-2007 06:49
24-Oct-2007 06:49
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;
}
?>
Janez R.
31-Jul-2007 12:27
31-Jul-2007 12:27
--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;
}
?>
yuki [dot] kodama [at] gmail [dot] com
01-Feb-2007 01:56
01-Feb-2007 01:56
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);
}
?>
bdechka at yahoo dot ca
10-Jan-2007 05:57
10-Jan-2007 05:57
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";
?>
marcel dot oehler at kubusmedia dot com
09-Feb-2006 12:26
09-Feb-2006 12:26
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...
Seanj.jcink.com
05-Jan-2006 11:23
05-Jan-2006 11:23
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.
ildar [DASH] sh [AT] mail [DOT] ru
30-Nov-2005 03:02
30-Nov-2005 03:02
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
david dot tulloh at infaze dot com dot au
23-Jun-2005 05:18
23-Jun-2005 05:18
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.
bishop
01-May-2004 12:19
01-May-2004 12:19
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
?>
tonicpeddler at aol dot com
02-Nov-2002 12:17
02-Nov-2002 12:17
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
php dot net at cuntbubble dot com
18-Jan-2002 01:08
18-Jan-2002 01:08
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 > 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 :)
