2012-07-19 21 views
13

Estoy acostumbrado a la función map() de perl, donde la devolución de llamada puede asignar tanto la clave como el valor, creando así una matriz asociativa donde la entrada era una matriz plana. Soy consciente de array_fill_keys() que puede ser útil si todo lo que quieres hacer es crear un hash de estilo de diccionario, pero ¿qué pasa si no necesariamente quieres que todos los valores sean iguales? Obviamente, todas las cosas se pueden hacer con la iteración foreach, pero ¿qué otros métodos (posiblemente más elegantes) existen?¿Cómo convertir una matriz de matrices u objetos a una matriz asociativa?

Editar: agregando un ejemplo para aclarar la transformación. Por favor, no te obsesiones con la transformación, la cuestión es transformar una lista plana en un hash donde no podemos suponer que todos los valores serán los mismos.

$original_array: ('a', 'b', 'c', 'd') 
$new_hash: ('a'=>'yes', 'b'=>'no', 'c'=>'yes', 'd'=>'no') 

*note: the values in this example are arbitrary, governed by some business logic that is not really relevant to this question. For example, perhaps it's based on the even-oddness of the ordinal value of the key 

mundo real Ejemplo Por lo tanto, el uso de una respuesta que fue proporcionada aquí, aquí es cómo se puede analizar a través de los $ _POST para obtener una lista de esos campos de entrada que responden a un criterio dado. Esto podría ser útil, por ejemplo, si tiene muchos campos de entrada en su formulario, pero un cierto grupo de ellos debe procesarse en conjunto.

En este caso, tengo una serie de campos de entrada que representan asignaciones a una base de datos. Cada uno de los campos de entrada se ve así: <input name="field-user_email" value="2" /> donde cada uno de este tipo de campo tiene el prefijo "campo-".

lo que queremos hacer es, primero, obtener una lista de solo aquellos campos de entrada que en realidad comienzan con "campo-", entonces queremos crear una matriz asociativa llamada $mapped_fields que tiene el nombre de campo extraído como la clave y el valor real del campo de entrada como el valor.

$mapped_fields = array_reduce(preg_grep('/field-.+/', array_keys($_POST)), function($hash, $field){ $hash[substr($field, 6)] = $_POST[$field]; return $hash; }); 

que da salida:

Array ([date_of_birth] => 1 [user_email] => 2 [last_name] => 3 [first_name] => 4 [current_position] => 6) 

(Por lo tanto, sólo para impedir que los detractores, déjame acuerdo en que este trozo de código compacto es sin duda mucho menos legible que un bucle simple que itera a través de $ _POST y, para cada clave, comprueba si tiene el prefijo, y si es así, lo muestra y su valor en una matriz)

+0

¿Se puede publicar un volcado de la matriz (usando 'print_r' o' var_dump')? – Florent

+1

@Florent done ... –

Respuesta

29

que tenían el mismo problema hace unos días. No es posible usar array_map, pero array_reduce hace el truco.

$arr = array('a','b','c','d'); 
$assoc_arr = array_reduce($arr, function ($result, $item) { 
    $result[$item] = (($item == 'a') || ($item == 'c')) ? 'yes' : 'no'; 
    return $result; 
}, array()); 
var_dump($assoc_arr); 

resultado:

array(4) { ["a"]=> string(3) "yes" ["b"]=> string(2) "no" ["c"]=> string(3) "yes" ["d"]=> string(2) "no" }

+1

Guau, nunca se me ocurrió usar array_reduce de esta forma, suponiendo que siempre fue solo para devolver un valor escalar. En retrospectiva, es discutible si este enfoque es de alguna manera preferible al método foreach mencionado anteriormente por @minitech. ¡Pero es muy agradable ver tu alternativa! Gracias por publicar. –

+0

Método inteligente. Esto a menudo es muy útil. – Ikke

+0

Estoy de acuerdo con Tom Auger, es cuestionable si uno debe usar este método. Incluso si gana por el lado del rendimiento (que no estoy seguro), pierde legibilidad en comparación con una declaración foreach habitual. Elegante, sin embargo;) –

2

Por lo que sé, es completamente imposible en una expresión, por lo que puede bien utilizar un foreach lazo, à la

$new_hash = array(); 

foreach($original_array as $item) { 
    $new_hash[$item] = 'something'; 
} 

Si lo necesita en una sola expresión, seguir adelante y hacer una función:

function array_map_keys($callback, $array) { 
    $result = array(); 

    foreach($array as $item) { 
     $r = $callback($item); 

     $result[$r[0]] = $r[1]; 
    } 

    return $result; 
} 
2

Esta es una aclaración sobre mi comentario en el método aceptado. Afortunadamente más fácil de leer.Esto es de una clase de WordPress, por lo tanto la referencia $ wpdb a escribir los datos:

class SLPlus_Locations { 
    private $dbFields = array('name','address','city'); 

    public function MakePersistent() { 
     global $wpdb; 
     $dataArray = array_reduce($this->dbFields,array($this,'mapPropertyToField')); 
     $wpdb->insert('wp_store_locator',$dataArray); 
    } 

    private function mapPropertyToField($result,$property) { 
     $result[$property] = $this->$property; 
     return $result; 
    } 
} 

Obviamente hay un poco más a la solución completa, pero las partes pertinentes a array_reduce() están presentes. Más fácil de leer y más elegante que un foreach o forzar el problema a través de array_map() más una declaración de inserción personalizada.

¡Agradable!

+0

Siendo un poco fanático de los anticuados y del código obfu al estilo Perl, esta ha sido mi solución preferida, incluso en proyectos de producción. Bonito, y gracias por regresar para ofrecer otra solución. –

Cuestiones relacionadas