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.