PHP’s had array_chunk for a while, which splits an array into groups of a certain size. The Ruby equivalent is each_slice from Enumerator, recently joined by some Rails goodies in the form of Enumerable#group_by and Array#in_groups_of.
in_groups_of is just a slightly enhanced wrapper around each_slice, which gives it array_chunk’s ability to pad out groups. But PHP doesn’t seem to have anything like group_by, which lets you split the elements on some criteria. And because group_by takes a block, you can create nested groups to put the elements in whatever hierarchy you like.
So I’ve chucked together a function to do something similar:
function array_group($array, $callback) {
return array_reduce(array_map($callback, $array), 'array_merge_recursive');
}
array_group expects $callback to take the element and put it into an array thusly:
array($top_level => array($mid_level => array($bottom_level => $element)));
The callback builds a mini hierarchy-of-one for each element, and then it’s all merged together. For example:
function group(&$element) {
if (is_int($element)) {
$top = 'number';
} else if ($element == strtolower($element)) {
$top = 'lower';
} else if ($element == strtoupper($element)) {
$top = 'upper';
}
$bottom = strlen($element) > 6 ? 'long' : 'short';
return array($top => array($bottom => $element));
}
$array = array("lower", "UPPER", 12345, "lower lower", "UPPER UPPER", 1234567890);
var_dump(array_group($array, 'group'));
Gives you:
array(3) {
["lower"]=>
array(2) {
["short"]=>
string(5) "lower"
["long"]=>
string(11) "lower lower"
}
["upper"]=>
array(2) {
["short"]=>
string(5) "UPPER"
["long"]=>
string(11) "UPPER UPPER"
}
["number"]=>
array(2) {
["short"]=>
int(12345)
["long"]=>
int(1234567890)
}
}
I’m pretty sure that this implementation will lose any references inside the array, and I don’t think you can avoid that with all the array_map/reduce/merge_recursive stuff. If this is an issue for you, you’ll probably have to write something uglier (which I’d still like to see).
It still feels a bit clunky, but all in all it’s about as elegant as PHP gets, and it’s a nice demo of functional programming in the language.