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'appel 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
.
Utilisation
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k, 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Sortie
array(3) {
["new first"]=>
string(7) "new 1st"
["new second"]=>
string(7) "new 2nd"
["new third"]=>
string(7) "new 3rd"
}
Application partielle
Si vous devez utiliser la fonction plusieurs fois avec des tableaux différents mais la même fonction de mappage, vous pouvez faire quelque chose qui s'appelle application d'une fonction partielle (lié à ' curry '), ce qui permet de ne transmettre que le tableau de données lors de 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));
Ce qui produit le même résultat, étant donné que $func
y $ordinals
sont les mêmes que précédemment.
REMARQUE : si votre fonction cartographiée renvoie la valeur même clé pour deux entrées différentes, la valeur associée à la clé la plus tardive l'emportera. Inverser le tableau d'entrée et le résultat de sortie de array_map_assoc
pour permettre aux clés antérieures de l'emporter. (Dans mon exemple, les clés renvoyées ne peuvent pas entrer en collision, car elles intègrent la clé du tableau source, qui doit à son tour être unique).
Alternative
Voici une variante de ce qui précède, qui pourrait s'avérer plus logique pour certains, mais qui 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, la fonction fournie (sur laquelle le tableau de données est mappé) doit renvoyer un tableau associatif d'une ligne, c'est-à-dire return [key => value]
. Le résultat du mappage de l'objet appelable est alors simplement décompressé et transmis à array_merge
. Comme précédemment, le fait de renvoyer une clé dupliquée aura pour effet de faire gagner les valeurs ultérieures.
n.b. Alex83690 a noté dans un commentaire que l'utilisation de 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, et est donc sans danger pour le code fonctionnel.
Si vous êtes en PHP 5.3 à 5.5, ce qui suit est équivalent. Il utilise array_reduce
et le code 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;
}, []);
}
Utilisation
Ces deux variantes seraient ainsi utilisées :
$ordinals = [
'first' => '1st',
'second' => '2nd',
'third' => '3rd',
];
$func = function ($k, $v) {
return ['new ' . $k => 'new ' . $v];
};
var_dump(array_map_assoc($func, $ordinals));
Notez que les =>
au lieu de ,
en $func
.
Le résultat est le même que précédemment, et chacun peut être partiellement appliqué de la même manière que précédemment.
Résumé
L'objectif de la question initiale est de rendre l'invocation de l'appel aussi simple que possible, au détriment de l'invocation d'une fonction plus compliquée ; en particulier, il s'agit de pouvoir passer le tableau de données en tant qu'argument unique, 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 simplifier en disant array_map_assoc()
qui supprime les clés de sortie, puisque 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));
La réponse est donc NON vous ne pouvez pas éviter d'appeler array_keys
mais vous pouvez faire abstraction de l'endroit où array_keys
est appelé dans une fonction d'ordre supérieur, ce qui peut être suffisant.