Ecco la mia soluzione molto semplice e compatibile con PHP 5.5:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
Il callable che fornisci dovrebbe restituire un array con due valori, vale a dire return [key, value]
. La chiamata interna a array_map
quindi produce una matrice di matrici. Questo viene quindi riconvertito in un array monodimensionale da array_column
.
uso
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Produzione
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Applicazione parziale
Nel caso in cui sia necessario utilizzare la funzione più volte con matrici diverse ma con la stessa funzione di mappatura, è possibile eseguire qualcosa chiamato applicazione di funzione parziale (correlata a ' curry '), che consente di passare nell'array di dati solo su chiamata:
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));
Che produce lo stesso output, dato $func
e $ordinals
sono come prima.
NOTA: se la funzione mappata restituisce la stessa chiave per due input diversi, il valore associato alla chiave successiva vincerà. Invertire la matrice di input e il risultato di output array_map_assoc
per consentire ai tasti precedenti di vincere. (Le chiavi restituite nel mio esempio non possono scontrarsi perché incorporano la chiave dell'array di origine, che a sua volta deve essere unica.)
Alternativa
Di seguito è una variante di quanto sopra, che potrebbe rivelarsi più logico per alcuni, ma richiede PHP 5.6:
function array_map_assoc(callable $f, array $a) {
return array_merge(...array_map($f, array_keys($a), $a));
}
In questa variante, la funzione fornita (su cui è mappata la matrice di dati) dovrebbe invece restituire una matrice associativa con una riga, ad es return [key => value]
. Il risultato della mappatura del callable viene quindi semplicemente decompresso e passato a array_merge
. Come in precedenza, la restituzione di una chiave duplicata comporterà la vincita dei valori successivi.
nb Alex83690 ha notato in un commento che l'utilizzo array_replace
qui invece di array_merge
preservare le chiavi intere. array_replace
non modifica l'array di input, quindi è sicuro per il codice funzionale.
Se usi PHP da 5.3 a 5.5, il seguente è equivalente. Utilizza array_reduce
e l' +
operatore di array binario per convertire l'array bidimensionale risultante in un array unidimensionale preservando le chiavi:
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;
}, []);
}
uso
Entrambe queste varianti verrebbero utilizzate così:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Nota =>
invece di ,
in $func
.
L'output è lo stesso di prima e ognuno può essere parzialmente applicato come prima.
Sommario
L'obiettivo della domanda originale è rendere l'invocazione della chiamata il più semplice possibile, a scapito di avere una funzione più complicata che viene invocata; in particolare, avere la possibilità di passare l'array di dati come singolo argomento, senza suddividere le chiavi e i valori. Utilizzando la funzione fornita all'inizio di questa risposta:
$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)));
Oppure, solo per questa domanda, possiamo semplificare la array_map_assoc()
funzione che elimina le chiavi di output, poiché la domanda non le chiede:
$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));
Quindi la risposta è NO , non puoi evitare di chiamare array_keys
, ma puoi astrarre il posto in cui array_keys
viene chiamato in una funzione di ordine superiore, che potrebbe essere abbastanza buona.