Oto moje bardzo proste rozwiązanie kompatybilne z PHP 5.5:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
Podane przez Ciebie wywołanie powinno zwrócić tablicę z dwiema wartościami, tj return [key, value]
. Wewnętrzne wezwanie do array_map
tworzy zatem tablicę tablic. To następnie jest konwertowane z powrotem do tablicy jednowymiarowej przez array_column
.
Stosowanie
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Wynik
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Częściowe zastosowanie
W przypadku, gdy trzeba używać tej funkcji wiele razy z różnymi tablicami, ale z tą samą funkcją mapowania, można zrobić coś, co nazywa się aplikacją funkcji częściowej (związaną z „ curry ”), co pozwala na przekazanie tablicy danych tylko po wywołaniu:
function array_map_assoc_partial(callable $f) {
return function (array $a) use ($f) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
};
}
...
$my_mapping = array_map_assoc_partial($func);
var_dump($my_mapping($ordinals));
Który daje taką samą wydajność, podaną $func
i $ordinals
są jak wcześniej.
UWAGA: jeśli funkcja zamapowana zwraca ten sam klucz dla dwóch różnych danych wejściowych, wartość powiązana z późniejszym kluczem wygra. Odwróć tablicę wejściową i wynik wyjściowy, array_map_assoc
aby umożliwić wygrywanie wcześniejszym kluczom. (Zwrócone klucze w moim przykładzie nie mogą kolidować, ponieważ zawierają klucz tablicy źródłowej, która z kolei musi być unikalna).
Alternatywny
Poniżej przedstawiono wariant powyższego, który dla niektórych może okazać się bardziej logiczny, ale wymaga PHP 5.6:
function array_map_assoc(callable $f, array $a) {
return array_merge(...array_map($f, array_keys($a), $a));
}
W tym wariancie podana funkcja (na której odwzorowana jest tablica danych) powinna zamiast tego zwrócić tablicę asocjacyjną z jednym wierszem, tj return [key => value]
. Wynik mapowania wywoływanego elementu jest następnie po prostu rozpakowywany i przekazywany do array_merge
. Tak jak wcześniej, zwrócenie duplikatu klucza spowoduje wygraną późniejszych wartości.
nb Alex83690 zauważył w komentarzu, że użycie array_replace
tutaj w miejsce array_merge
zachowałoby klucze do liczb całkowitych. array_replace
nie modyfikuje tablicy wejściowej, więc jest bezpieczny dla kodu funkcjonalnego.
Jeśli korzystasz z PHP 5.3 do 5.5, poniższe są równoważne. Wykorzystuje array_reduce
i +
operator tablicy binarnej do konwersji wynikowej tablicy dwuwymiarowej na tablicę jednowymiarową przy jednoczesnym zachowaniu kluczy:
function array_map_assoc(callable $f, array $a) {
return array_reduce(array_map($f, array_keys($a), $a), function (array $acc, array $a) {
return $acc + $a;
}, []);
}
Stosowanie
Oba te warianty zostałyby wykorzystane w ten sposób:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Uwaga =>
zamiast ,
w $func
.
Dane wyjściowe są takie same jak poprzednio i każdy może być częściowo zastosowany w taki sam sposób jak poprzednio.
Podsumowanie
Pierwotne pytanie ma na celu uproszczenie wywołania wywołania kosztem posiadania bardziej skomplikowanej funkcji, która zostanie wywołana; szczególnie, aby mieć możliwość przekazania tablicy danych jako jednego argumentu, bez dzielenia kluczy i wartości. Korzystanie z funkcji dostarczonej na początku tej odpowiedzi:
$test_array = ["first_key" => "first_value",
"second_key" => "second_value"];
$array_map_assoc = function (callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
};
$f = function ($key, $value) {
return [$key, $key . ' loves ' . $value];
};
var_dump(array_values($array_map_assoc($f, $test_array)));
Lub, tylko dla tego pytania, możemy uprościć array_map_assoc()
funkcję, która upuszcza klucze wyjściowe, ponieważ pytanie nie wymaga ich:
$test_array = ["first_key" => "first_value",
"second_key" => "second_value"];
$array_map_assoc = function (callable $f, array $a) {
return array_map($f, array_keys($a), $a);
};
$f = function ($key, $value) {
return $key . ' loves ' . $value;
};
var_dump($array_map_assoc($f, $test_array));
Tak więc odpowiedź brzmi NIE , nie można uniknąć dzwonienia array_keys
, ale można wykreślić miejsce, w którym array_keys
wywoływana jest funkcja wyższego rzędu, co może być wystarczająco dobre.