2012-07-19 15 views
13

Jestem przyzwyczajony do funkcji perl's map(), w której callback może przypisać zarówno klucz, jak i wartość, tworząc w ten sposób tablicę asocjacyjną, w której wejście było płaską tablicą. Jestem świadomy array_fill_keys(), który może być przydatny, jeśli chcesz tylko utworzyć mieszanie stylu słownikowego, ale co jeśli nie wszystkie wartości będą takie same? Oczywiście wszystko można zrobić z iteracją foreach, ale jakie inne (być może bardziej eleganckie) metody istnieją?Jak przekonwertować tablicę tablic lub obiektów na tablicę asocjacyjną?

Edytuj: dodając przykład, aby wyjaśnić transformację. Proszę nie zwlekać z transformacją, chodzi o przekształcenie płaskiej listy w skrót, w którym nie możemy założyć, że wszystkie wartości będą takie same.

$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 

rzeczywistym świecie Przykład Więc korzystając odpowiedź dostarczonego tutaj, oto jak można analizować poprzez $ _POST, aby uzyskać listę tylko tych pól wejściowych pasujących do danego kryteria. Może to być przydatne, na przykład, jeśli masz wiele pól wejściowych w formularzu, ale pewna grupa z nich musi być przetwarzana razem.

W tym przypadku mam wiele pól wejściowych reprezentujących odwzorowania do bazy danych. Każde z pól wejściowych wygląda następująco: <input name="field-user_email" value="2" />, gdzie każde pole tego typu jest poprzedzone prefiksem "pole-".

chcemy najpierw uzyskać listę tylko tych pól wejściowych, które faktycznie zaczynają się od "field-", następnie chcemy utworzyć tablicę asocjacyjną o nazwie $mapped_fields, która ma wyodrębnioną nazwę pola jako klucz i faktyczna wartość pola wejściowego jako wartość.

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

które wyjścia:

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

(Tak, tak, aby zapobiec naysayers, pozwól mi zgodzić się, że ten kawałek kodu kompaktowej jest zapewne o wiele mniej czytelny, że prosta pętla że iteracje przez $ _POST i, dla każdego klucza, sprawdza, czy ma on prefiks, a jeśli tak, wyrzuca go i jego wartość na tablicę)

+0

Czy możesz wysłać zrzut tablicy (używając 'print_r' lub' var_dump')? – Florent

+1

@Florent done ... –

Odpowiedz

29

miałem dokładnie ten sam problem kilka dni temu. Nie jest to możliwe przy użyciu array_map, ale array_reduce robi lewę.

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

wynik:

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

+1

Wow, nigdy nie przyszło mi do użycia array_reduce w ten sposób - stwierdzając, że zawsze miał po prostu zwracać wartość skalarną. Z perspektywy czasu można stwierdzić, czy to podejście jest w jakikolwiek sposób lepsze od wspomnianej powyżej metody @minitech. Ale miło jest zobaczyć swoją alternatywę! Dzięki za publikację. –

+0

Sprytna metoda. Bardzo często jest to bardzo przydatne – Ikke

+0

Zgadzam się z Tomem Augerem, to wątpliwe, czy należy używać tej metody. Nawet jeśli wygrasz po stronie wydajności (której nie jestem pewien), stracisz czytelność w porównaniu do zwykłego oświadczenia foreach. Elegancki jednak;) –

2

O ile mi wiadomo, jest to całkowicie niemożliwe w jednym wyrażeniu, więc możesz jako użyj pętli foreach, a la

$new_hash = array(); 

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

Jeśli jest to potrzebne w jednym wyrażeniu, należy iść dalej i uczynić funkcję:

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

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

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

    return $result; 
} 
2

Jest to wyjaśnienie na mój komentarz w przyjętej metody. Mam nadzieję, że łatwiej je przeczytać.Jest to z WordPress klasy, stąd odniesienie wpdb $ do zapisu danych:

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

Oczywiście jest nieco bardziej do kompletnego rozwiązania, ale części dotyczące array_reduce() są obecne. Łatwiejsze do odczytania i bardziej eleganckie niż foreach lub zmuszające do wydania poprzez array_map() plus niestandardową instrukcję wstawiania.

Nice!

+0

Będąc odrobinę przyssawką dla jednego liniowca i kodu obfu w stylu Perla, to było moje najlepsze rozwiązanie, nawet w projektach produkcyjnych. Fajna, i dziękuję za powrót, aby zapewnić inne rozwiązanie. –