2012-07-19 13 views
13

Sono abituato alla funzione map() di perl, in cui il callback può assegnare sia la chiave che il valore, creando così un array associativo in cui l'input era un array piatto. Sono a conoscenza di array_fill_keys() che può essere utile se tutto ciò che si vuole fare è creare un hash in stile dizionario, ma cosa succede se non si desidera necessariamente che tutti i valori siano uguali? Ovviamente tutte le cose possono essere fatte con foreach iteration, ma quali altri (possibilmente più eleganti) metodi esistono?Come convertire un array di matrici o oggetti in un array associativo?

Modifica: aggiunta di un esempio per chiarire la trasformazione. Per favore non rimanere impigliato nella trasformazione, la domanda è trasformare una lista piatta in un hash in cui non possiamo assumere che tutti i valori saranno gli stessi.

$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 

mondo reale Esempio Quindi, utilizzando una risposta che è stata fornita qui, ecco come si potrebbe analizzare attraverso il $ _POST per ottenere un elenco di quei campi di input che corrispondono a un dato criterio. Ciò potrebbe essere utile, ad esempio, se nel modulo sono presenti molti campi di input, ma un determinato gruppo di essi deve essere elaborato insieme.

In questo caso, ho un numero di campi di input che rappresentano i mapping a un database. Ognuno dei campi di input è simile al seguente: <input name="field-user_email" value="2" /> dove ognuno di questo tipo di campo è preceduto da "campo-".

quello che vogliamo fare è, in primo luogo, ottenere un elenco solo di quei campi di input che effettivamente iniziano con "field-", quindi vogliamo creare un array associativo chiamato $mapped_fields che ha il nome del campo estratto come chiave e il valore del campo di input effettivo come valore.

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

quali uscite:

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

(Così, tanto per anticipare gli oppositori, mi permetta d'accordo che questo pezzo di codice compatto è probabilmente molto meno leggibile che un semplice ciclo che consente di scorrere $ _POST e, per ogni chiave, controlla se ha il prefisso e, in caso affermativo, lo apre e il suo valore su un array)

+0

Puoi pubblicare un dump dell'array (usando 'print_r' o' var_dump')? – Florent

+1

@Florent done ... –

risposta

29

ho avuto lo stesso problema qualche giorno fa. Non è possibile utilizzare array_map, ma il array_reduce fa il trucco.

$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); 

risultato:

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

+1

Wow, non mi è mai venuto in mente di usare array_reduce in questo modo - immaginando che fosse sempre pensato solo per restituire un valore scalare. In retrospettiva, è discutibile se questo approccio sia in qualche modo preferibile al metodo di foreach, menzionando @minitech, sopra. Ma è molto bello vedere la tua alternativa! Grazie per la pubblicazione. –

+0

Metodo intelligente. Questo spesso è molto utile – Ikke

+0

In realtà sono d'accordo con Tom Auger, è discutibile se si dovrebbe usare questo metodo. Anche se vinci dal lato prestazioni (cosa di cui non sono sicuro), perdi la leggibilità rispetto a una normale dichiarazione foreach. Elegante però;) –

2

Per quanto ne so, è completamente impossibile in un'espressione, quindi è possibile bene utilizzare un ciclo foreach, à la

$new_hash = array(); 

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

Se avete bisogno in una sola espressione, andare avanti e fare una funzione:

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

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

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

    return $result; 
} 
2

Si tratta di un chiarimento sul mio commentare nel metodo accettato. Spero sia più facile da leggere.Questo è da una classe di WordPress, quindi il riferimento wpdb $ per scrivere i dati:

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; 
    } 
} 

Ovviamente c'è un po 'di più per la soluzione completa, ma le parti rilevanti per array_reduce() sono presenti. Più facile da leggere e più elegante di un foreach o forzare il problema tramite array_map() più un'istruzione di inserimento personalizzata.

Bello!

+0

Essendo un po 'ficcanaso per one-liner e codice OFO in stile Perl, questa è stata la mia soluzione ideale, anche nei progetti di produzione. Bello, e grazie per essere tornato a fornire un'altra soluzione. –

Problemi correlati