PHP: Czy mogę uzyskać indeks w funkcji array_map?

87

Używam mapy w php w następujący sposób:

function func($v) {
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map(func, $values);
var_dump($mapped);

Czy można uzyskać indeks wartości w funkcji?

Ponadto - jeśli piszę kod, który wymaga indeksu, czy powinienem używać pętli for zamiast mapy?

Ollie Glass
źródło

Odpowiedzi:

215

Jasne, że możesz, z pomocą array_keys():

function func($v, $k)
{
    // key is now $k
    return $v * 2;
}

$values = array(4, 6, 3);
$mapped = array_map('func', $values, array_keys($values));
var_dump($mapped);
Aron Rotteveel
źródło
20
Fajna odpowiedź, nie zdawałem sobie sprawy, że możesz przekazać dodatkowe parametry do metody array_map () ped. Dowiedz się czegoś nowego każdego dnia!
GordonM
1
@Gordon yeah możesz podać array_map()dowolną liczbę argumentów :)
Aron Rotteveel
13
Jest to bardzo ryzykowne podejście, ponieważ PHP nie gwarantuje, że klucze zwrócone przez array_keyspozostaną w tej samej kolejności, co w oryginalnej tablicy. W związku z tym możesz skończyć mapowaniem kluczy na złe wartości. Bezpiecznym podejściem jest użycie tylko array_keysdrugiego argumentu polecenia, array_mapa następnie przekazanie tablicy do zamknięcia za pomocą useinstrukcji.
user487772
12
Szczerze mówiąc nie rozumiem, dlaczego PHP nie ma funkcji mapowania, która dostarcza klucz każdego elementu jako drugi parametr wywołania zwrotnego.
grypa
1
@flu PHP nie zasłużyło na tytuł wulgarnego języka bez powodu.
xZero
9

Podczas mapowania anonimowej funkcji na anonimową tablicę nie ma możliwości uzyskania dostępu do kluczy:

array_map(
    function($val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

array_reduce również nie ma dostępu do kluczy. array_walk może uzyskać dostęp do kluczy, ale tablica jest przekazywana przez odwołanie, co wymaga warstwy pośredniej.

Oto niektóre rozwiązania:

Tablica par

To źle, ponieważ zmieniamy oryginalną tablicę. Dodatkowo wywołania „array ()” na poziomie standardowym rosną liniowo wraz z długością tablicy:

array_map(
    function($pair) use ($foo) {
        list($key, $val) = $pair;
        /* ... */
    },
    array(array(key1, val1),
          array(key2, val2),
          /* ... */));

Zmienna tymczasowa

Działamy na oryginalnej tablicy, a schemat standardowy jest stały, ale możemy łatwo przebić istniejącą zmienną:

$i_hope_this_does_not_conflict = array(key1 => val1,
                                       key2 => val2,
                                       /* ... */);
array_map(
    function($key, $val) use ($foo) { /* ... */ },
    array_keys($i_hope_this_does_not_conflict),
    $i_hope_this_does_not_conflict);
unset($i_hope_this_does_not_conflict);

Funkcja jednorazowego użytku

Możemy użyć zakresu funkcji, aby zapobiec przebijaniu istniejących nazw, ale musimy dodać dodatkową warstwę „użytkowania”:

call_user_func(
    function($arr) use ($foo) {
        return array_map(function($key, $val) use ($foo) { /* ... */ },
                         array_keys($arr),
                         $arr);
    },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Wieloargumentowa funkcja jednorazowa

Definiujemy funkcję, którą mapujemy w oryginalnym zakresie, aby zapobiec użyciu schematu „użyj”):

call_user_func(
    function($f, $arr) {
        return array_map($f, array_keys($arr), $arr);
    },
    function($key, $val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Nowa funkcja

Warto zauważyć, że nasza ostatnia jednorazowa funkcja ma ładny, ogólny podpis i wygląda bardzo podobnie do tablicy array_map. Możemy chcieć nadać temu nazwę i użyć go ponownie:

function array_mapk($f, $arr) {
    return array_map($f, array_keys($arr), $arr);
}

Nasz kod aplikacji staje się wtedy:

array_mapk(
    function($key, $val) use ($foo) { /* ... */ },
    array(key1 => val1,
          key2 => val2,
          /* ... */));

Pośredni spacer po szyku

Pisząc powyższe, zignorowałem array_walk, ponieważ wymaga ona przekazania argumentu przez referencję; jednak od tego czasu zdałem sobie sprawę, że można łatwo obejść ten problem za pomocą call_user_func. Myślę, że to jak dotąd najlepsza wersja:

call_user_func(
    'array_walk',
    array(key1 => val1,
          key2 => val2,
          /* ... */),
    function($val, $key) use ($foo) { /* ... */ });
Warbo
źródło
1

Bardzo proste:

Tylko funkcja array_map: nie ma klucza indeksu!

 $params = [4,6,2,11,20];

 $data = array_map(function($v) { return ":id{$v}";}, $params);

 array (size=5)
  0 => string ':id4' (length=4)
  1 => string ':id6' (length=4)
  2 => string ':id2' (length=4)
  3 => string ':id11' (length=5)
  4 => string ':id20' (length=5)

Teraz połącz z array_keys:

$data = array_map(
    function($k) use ($params) { return ":id{$k}_${params[$k]}"; },
    array_keys($params)
 );

array (size=5)
  0 => string ':id0_4' (length=6)
  1 => string ':id1_6' (length=6)
  2 => string ':id2_2' (length=6)
  3 => string ':id3_11' (length=7)
  4 => string ':id4_20' (length=7)
Fábio Zangirolami
źródło
0

Możesz stworzyć własną funkcję mapy za pomocą foreach:

<?php

function myCallback($key, $val)
{
    var_dump("myCallback - key: $key, val: $val");
    return $val * 2;
}

function foreachMap($callback, $givenArray) {
    $result = [];
    foreach ($givenArray as $key=>$val) {
        $result[$key] = $callback($key, $val);
    }
    return $result;
}

$values = array(4, 6, 3);
$mapped = foreachMap('myCallback', $values);
var_dump($mapped);

spróbuj: https://3v4l.org/pmFlB

domis86
źródło