Voici ma solution très simple, compatible avec PHP 5.5:
function array_map_assoc(callable $f, array $a) {
return array_column(array_map($f, array_keys($a), $a), 1, 0);
}
L'appelable que vous fournissez doit lui-même renvoyer un tableau avec deux valeurs, c'est-à-dire return [key, value]
. L'appel interne à array_map
produit donc un tableau de tableaux. Celui-ci est ensuite reconverti en un tableau à une dimension par array_column
.
Usage
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Production
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Application partielle
Dans le cas où vous devez utiliser la fonction plusieurs fois avec des tableaux différents mais la même fonction de mappage, vous pouvez faire quelque chose appelé application de fonction partielle (liée au `` currying ''), qui vous permet de ne transmettre le tableau de données qu'à l'invocation:
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));
Qui produit la même sortie, donnée $func
et $ordinals
sont comme précédemment.
REMARQUE: si votre fonction mappée renvoie la même clé pour deux entrées différentes, la valeur associée à la dernière clé gagnera. Inversez le tableau d'entrée et le résultat de sortie array_map_assoc
pour permettre aux clés antérieures de gagner. (Les clés renvoyées dans mon exemple ne peuvent pas entrer en collision car elles incorporent la clé du tableau source, qui à son tour doit être unique.)
Alternative
Voici une variante de ce qui précède, qui pourrait s'avérer plus logique pour certains, mais nécessite PHP 5.6:
function array_map_assoc(callable $f, array $a) {
return array_merge(...array_map($f, array_keys($a), $a));
}
Dans cette variante, votre fonction fournie (sur laquelle le tableau de données est mappé) devrait plutôt renvoyer un tableau associatif avec une ligne, c'est-à-dire return [key => value]
. Le résultat du mappage de l'appelable est ensuite simplement décompressé et transmis à array_merge
. Comme précédemment, le retour d'une clé en double entraînera la victoire des valeurs ultérieures.
nb Alex83690 a noté dans un commentaire que l'utilisation array_replace
ici à la place de array_merge
préserverait les clés entières. array_replace
ne modifie pas le tableau d'entrée, est donc sans danger pour le code fonctionnel.
Si vous utilisez PHP 5.3 à 5.5, ce qui suit est équivalent. Il utilise array_reduce
et l' +
opérateur de tableau binaire pour convertir le tableau bidimensionnel résultant en un tableau unidimensionnel tout en préservant les clés:
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;
}, []);
}
Usage
Ces deux variantes seraient utilisées ainsi:
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Notez le =>
au lieu de ,
dans $func
.
La sortie est la même qu'avant, et chacune peut être partiellement appliquée de la même manière qu'auparavant.
Résumé
Le but de la question d'origine est de rendre l'appel de l'appel aussi simple que possible, au détriment d'avoir une fonction plus compliquée qui est invoquée; en particulier, pour pouvoir passer le tableau de données en un seul argument, sans diviser les clés et les valeurs. En utilisant la fonction fournie au début de cette réponse:
$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)));
Ou, pour cette question uniquement, nous pouvons faire une simplification de la array_map_assoc()
fonction qui supprime les clés de sortie, car la question ne les demande pas:
$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));
Donc, la réponse est NON , vous ne pouvez pas éviter d'appeler array_keys
, mais vous pouvez faire abstraction de l'endroit où array_keys
est appelé une fonction d'ordre supérieur, ce qui pourrait être suffisant.