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?

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

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) { /* ... */ });

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)

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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.