Schwartzian transform in PHP
It's no Perl for sure, but can PHP speak with a Lisp?
Ah, the Schwartzian transform. Is there some way to do this in PHP, that is “speak PHP with a Lisp”?
Use the Schwartz, Luke
Let’s say we have an array of thousands of things, numbers in this case:
$array = array();
for ($i=0; $i < 100000; $i++) {
$array[] = $i;
}
For some reason, we want to sort this array by each array element’s MD5 hash. Here’s the naïve PHP sort:
function custom_sort($a, $b) {
return strcmp(md5($a), md5($b));
}
usort($array, 'custom_sort');
In PHP 5.3 and above, we could use a closure. Otherwise, create_function()
does almost the same thing very succinctly:
usort($array, create_function('$a,$b', 'return strcmp(md5($a), md5($b));'));
Now that I know how to benchmark PHP, I wanted some timings to compare. Here on my traveling laptop (a trusty old Powerbook G4 1.5GHz) the sort takes about 33 seconds.
Decorate-sort-undecorate
The point of the Schwartzian transform is to perform the expensive operation (the MD5 hash) just once per object. Here’s how it looks in PHP:
// decorate
array_walk($array, create_function('&$v, $k', '$v = array($v, md5($v));'));
// sort
usort($array, create_function('$a,$b', 'return strcmp($a[1], $b[1]);'));
// undecorate
array_walk($array, create_function('&$v, $k', '$v = $v[0];'));
It doesn’t look all nicely chained together as it does in Perl, but it works.
How’s the timing? 15 seconds, a more than 50% reduction!
How it works
PHP’s little-used array_walk()
takes the place of Perl’s map
: it performs some action on every element in an array. If you pass in an array reference (&$v
rather than plain old $v
) you can also edit the array elements in-place.
Have a look at the array_walk() documentation for more details.
Useful? Got a better way to do it? Share!