1

Is there a way to sort a PHP array by return value of a key function? Like Python's sorted(arr, key=keyfn) or Clojure's (sort-by keyfn arr),

usort($array, function ($a, $b) {
     $key_a = keyfn($a);
     $key_b = keyfn($b);
     if ($key_a == $key_b) return 0;
     if ($key_a < $key_b) return -1;
     return 1;
});

does what I want, but it's verbose and it calls keyfn (which can be slow) much more often than needed

0x60
  • 2,946
  • 1
  • 14
  • 17

2 Answers2

1

Some simple code for caching results of predicate and sorting (using spaceship operator which reduces lines where you return 0,1,-1). In case of predicate result as int you can even return $key_a - $key_b:

$array = [2,2,2,1,1,0,0,8];
$values_cache = [];
usort($array, function ($a, $b) use (&$values_cache) {
    $key_a = isset($values_cache[$a]) ? $values_cache[$a] : ($values_cache[$a] = keyfn($a));
    $key_b = isset($values_cache[$b]) ? $values_cache[$b] : ($values_cache[$b] = keyfn($b));
    return $key_a <=> $key_b;
});
echo '<pre>', print_r($array), '</pre>';

function keyfn($v) {
    echo 'call a keyfn' . PHP_EOL;
    return 2 * $v;
}

Simple fiddle https://3v4l.org/W1N7Y

u_mulder
  • 53,091
  • 5
  • 44
  • 59
1

I ended up implementing it this way:

function sort_by($key_f, $arr) {
    $values = array_map($key_f, $arr);
    asort($values);
    $sorted_arr = array();

    foreach ($values as $idx => $value) {
        $sorted_arr[] = $arr[$idx];
    }

    return $sorted_arr;
}
0x60
  • 2,946
  • 1
  • 14
  • 17