¿Hay alguna manera de hacer algo como esto?
$test_array = array("first_key" => "first_value",
"second_key" => "second_value");
var_dump(array_map(function($a, $b) { return "$a loves $b"; },
array_keys($test_array),
array_values($test_array)));
Pero en lugar de llamar array_keys
y array_values
, ¿pasar directamente la $test_array
variable?
La salida deseada es:
array(2) {
[0]=>
string(27) "first_key loves first_value"
[1]=>
string(29) "second_key loves second_value"
}
php
functional-programming
José Tomás Tocino
fuente
fuente
Respuestas:
No con array_map, ya que no maneja claves.
array_walk hace:
Sin embargo, cambia la matriz dada como parámetro, por lo que no es exactamente una programación funcional (ya que tiene la pregunta etiquetada así). Además, como se señaló en el comentario, esto solo cambiará los valores de la matriz, por lo que las claves no serán lo que especificó en la pregunta.
Si lo desea, puede escribir una función que arregle los puntos por encima de usted:
fuente
$a = "$b loves $a"
que coincida con la salida deseada del OP.array_walk()
que no devuelve la matriz resultante, sino un bool.Este es probablemente el más corto y fácil de razonar sobre:
fuente
array_keys()
. Sin embargo, eso parece un requisito tonto.Aquí está mi solución muy simple, compatible con PHP 5.5:
El invocable que proporcione debería devolver una matriz con dos valores, es decir
return [key, value]
. La llamada interna a,array_map
por lo tanto, produce una matriz de matrices. Esto se convierte de nuevo en una matriz de una sola dimensión porarray_column
.Uso
Salida
Aplicación parcial
En caso de que necesite usar la función muchas veces con diferentes matrices pero con la misma función de mapeo, puede hacer algo llamado aplicación de función parcial (relacionada con ' curry '), que le permite pasar solo la matriz de datos tras la invocación:
Lo que produce el mismo resultado, dado
$func
y$ordinals
son como antes.NOTA: si su función asignada devuelve la misma tecla para dos entradas diferentes, el valor asociado con la tecla posterior ganará. Invierta la matriz de entrada y el resultado de salida
array_map_assoc
para permitir que las teclas anteriores ganen. (Las claves devueltas en mi ejemplo no pueden colisionar ya que incorporan la clave de la matriz fuente, que a su vez debe ser única).Alternativa
La siguiente es una variante de lo anterior, que puede resultar más lógico para algunos, pero requiere PHP 5.6:
En esta variante, su función suministrada (sobre la cual se asigna la matriz de datos) debería devolver una matriz asociativa con una fila, es decir
return [key => value]
. El resultado de mapear el invocable simplemente se desempaqueta y se pasa aarray_merge
. Como antes, devolver una clave duplicada dará como resultado valores posteriores ganadores.Si está en PHP 5.3 a 5.5, lo siguiente es equivalente. Utiliza
array_reduce
y el+
operador de matriz binaria para convertir la matriz bidimensional resultante en una matriz unidimensional mientras conserva las claves:Uso
Ambas variantes se usarían así:
Tenga
=>
en cuenta el en lugar de,
en$func
.El resultado es el mismo que antes, y cada uno se puede aplicar parcialmente de la misma manera que antes.
Resumen
El objetivo de la pregunta original es hacer que la invocación de la llamada sea lo más simple posible, a expensas de tener una función más complicada que se invoca; especialmente, tener la capacidad de pasar la matriz de datos como un solo argumento, sin dividir las claves y los valores. Usando la función provista al comienzo de esta respuesta:
O, solo para esta pregunta, podemos hacer una simplificación de la
array_map_assoc()
función que elimina las teclas de salida, ya que la pregunta no las solicita:Entonces, la respuesta es NO , no puede evitar llamar
array_keys
, pero puede abstraer el lugar dondearray_keys
se llama a una función de orden superior, lo que podría ser lo suficientemente bueno.fuente
array_merge
porarray_replace
para preservar claves que serían enteros.Con PHP5.3 o posterior:
fuente
Así es como he implementado esto en mi proyecto.
fuente
¡Mira aquí! ¡Hay una solución trivial!
Como se indica en la pregunta,
array_map
ya tiene exactamente la funcionalidad requerida . Las otras respuestas aquí complicanarray_walk
demasiado las cosas: no es funcional.Uso
Exactamente como esperarías de tu ejemplo:
fuente
qrrqy_keys()
no debe usarse para #razonesPor "bucle manual" me refería a escribir una función personalizada que usa
foreach
. Esto devuelve una nueva matriz como loarray_map
hace porque el alcance de la función hace$array
que sea una copia, no una referencia:Sin embargo, su técnica
array_map
con usararray_keys
parece más simple y es más poderosa porque puede usarlanull
como devolución de llamada para devolver los pares clave-valor:fuente
unset( $value )
porque todavía existe en el alcance definido.Según la respuesta de eis , esto es lo que eventualmente hice para evitar estropear la matriz original:
fuente
array_walk
ya que no lo está haciendo referencia en el cierre.Hice esta función, basada en la respuesta de eis :
Ejemplo:
Salida:
Por supuesto, puede usar
array_values
para devolver exactamente lo que OP quiere.fuente
$arr
es de tipo matriz, sin embargo, si escribe una pista de sus argumentos comocallable
y enarray
su lugar puede soltar la verificaciónis_callable
. A continuación, realiza una asignación a $ value que luego no se utiliza. Simplemente debe ignorar el valor de retorno. En tercer lugar, sería mejor lanzar una excepción en la devolución de llamada que devolver falso. Entonces, siempre devolverá un valor válido o siempre arrojará.La biblioteca YaLinqo * es adecuada para este tipo de tarea. Es un puerto de LINQ de .NET que admite completamente valores y claves en todas las devoluciones de llamada y se asemeja a SQL. Por ejemplo:
o solo:
Aquí
'"$k loves $v"'
hay un acceso directo para la sintaxis de cierre completo que admite esta biblioteca.toArray()
Al final es opcional. La cadena de métodos devuelve un iterador, por lo que si el resultado solo necesita repetirse usandoforeach
, latoArray
llamada puede eliminarse.* desarrollado por mí
fuente
Haría algo como esto:
Resultados:
fuente
Agregaré otra solución al problema usando la versión 5.6 o posterior. No sé si es más eficiente que las soluciones ya excelentes (probablemente no), pero para mí es más simple de leer:
Usando
strval()
como una función de ejemplo en elarray_map
, esto generará:Espero no ser el único que encuentre esto bastante simple de entender.
array_combine
crea unakey => value
matriz a partir de una matriz de claves y una matriz de valores, el resto es bastante explicativo.fuente
Puede usar el método de mapa de esta biblioteca de matriz para lograr exactamente lo que desea tan fácilmente como:
También conserva las claves y devuelve una nueva matriz, sin mencionar algunos modos diferentes para satisfacer sus necesidades.
fuente
Fuente
fuente
Siempre me gusta la variante de JavaScript del mapa de matriz. La versión más simple sería:
Entonces, ahora puede pasarle una función de devolución de llamada cómo construir los valores.
fuente
h(g(f($data)))
aplicaf
, luegog
,h
a su datos. En general, se considera más versátil en la programación funcional tener una función que realice la misma operación en los datos de los buzos, que tener una función que aplique diversas funciones a un conjunto de datos fijo.Otra forma de hacer esto con (fuera) conservando claves:
fuente
Veo que falta la respuesta obvia:
Funciona exactamente como array_map. Casi.
En realidad, no es puro
map
como lo sabes de otros idiomas. Php es muy extraño, por lo que requiere algunas funciones de usuario muy extrañas, ya que no queremos romper nuestroworse is better
enfoque roto con precisión .Realmente, en realidad no es
map
en absoluto. Sin embargo, sigue siendo muy útil.La primera diferencia obvia de array_map es que la devolución de llamada toma salidas de
each()
cada matriz de entrada en lugar de solo el valor. Todavía puede iterar a través de más matrices a la vez.La segunda diferencia es la forma en que se maneja la clave después de que se devuelve de la devolución de llamada; El valor de retorno de la función de devolución de llamada debe ser
array('new_key', 'new_value')
. Las claves pueden y serán cambiadas, las mismas claves pueden incluso hacer que se sobrescriba el valor anterior, si se devuelve la misma clave. Este no es unmap
comportamiento común , pero le permite reescribir claves.La tercera cosa extraña es que, si omite el
key
valor de retorno (ya sea porarray(1 => 'value')
oarray(null, 'value')
), se asignará una nueva clave, como si$array[] = $value
se usara. Ese tampocomap
es el comportamiento común, sin embargo, a veces resulta útil, supongo.La cuarta cosa extraña es que, si la función de devolución de llamada no devuelve un valor, o devuelve
null
, todo el conjunto de claves y valores actuales se omite de la salida, simplemente se omite. Esta característica es totalmente unmap
py, sin embargo, haría de esta función un excelente truco doblearray_filter_assoc
, si existiera dicha función.Si omite el segundo elemento (
1 => ...
) (la parte del valor ) en el retorno de devolución de llamada,null
se utiliza en lugar del valor real.Cualquier otro elemento excepto aquellos con claves
0
y1
en el retorno de devolución de llamada se ignoran.Y, por último, si lambda devuelve cualquier valor excepto
null
o matriz, se trata como si se omitieran tanto la clave como el valor, por lo que:null
se usa como valorNOTA: a
diferencia de
array_map
, todos los parámetros que no son de matriz pasados aarray_map_assoc
, con la excepción del primer parámetro de devolución de llamada, se convierten silenciosamente en matrices.EJEMPLOS
// TODO: examples, anyone?
fuente