PHP: Чи можу я отримати індекс у функції array_map?


87

Я використовую карту в php так:

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

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

Чи можна отримати індекс значення у функції?

Крім того - якщо я пишу код, який потребує індексу, чи повинен я використовувати цикл for замість карти?

Відповіді:


215

Звичайно, ви можете за допомогою 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
Класна відповідь, не розумів, що ви можете передати зайві параметри в метод array_map () ped. Щодня дізнавайтеся щось нове!
GordonM

1
@Gordon, так, ви можете надати array_map()довільну кількість аргументів :)
Aron Rotteveel,

13
Це дуже ризикований підхід, оскільки PHP не гарантує, що ключі, що повертаються, array_keysзалишаться в тому ж порядку, що і в оригінальному масиві. Таким чином ви можете в кінцевому підсумку зіставити ключі з неправильними значеннями. Безпечний підхід полягає у використанні лише array_keysяк другого аргументу, array_mapа потім передачі масиву до закриття з useоператором.
user487772

13
Я відверто не розумію, чому PHP не має функції map, яка надає ключ кожного елемента як другий параметр зворотного виклику.
грип

1
@flu PHP не отримав звання поганої мови без причини.
xZero

9

При зіставленні анонімної функції з анонімним масивом неможливо отримати доступ до ключів:

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

array_reduce також не отримує доступу до ключів. array_walk може отримати доступ до ключів, але масив передається за посиланням, що вимагає рівня опосередкованості.

Деякі рішення:

Масив пар

Це погано, оскільки ми змінюємо вихідний масив. Плюс виклики шаблону "array ()" збільшуються лінійно зі збільшенням довжини масиву:

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

Тимчасова змінна

Ми діємо на вихідний масив, і шаблон є постійним, але ми можемо легко зняти наявну змінну:

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

Функція одного пострілу

Ми можемо використовувати сферу функцій, щоб запобігти обмеженню існуючих імен, але нам потрібно додати додатковий шар "use":

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

Багатоаргументальна одноразова функція

Ми визначаємо функцію, яку ми відображаємо, у вихідній області, щоб запобігти "використання" шаблонного шаблону):

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

Нова функція

Цікаво відзначити, що наша остання функція з одним знімком має гарний загальний підпис і дуже схожа на array_map. Можливо, ми хочемо назвати це ім’я та використати його повторно:

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

Тоді наш код програми стає:

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

Непряма прогулянка масивом

Під час написання вищезазначеного я ігнорував array_walk, оскільки він вимагає передачі аргументу за посиланням; проте з тих пір я зрозумів, що легко обійти це за допомогою call_user_func. Я думаю, що це найкраща версія на сьогодні:

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

1

Дуже просто:

Тільки функція array_map: не має ключа індексу!

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

Тепер комбінуйте з 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

Ви можете створити власну функцію карти за допомогою 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);

спробуйте: https://3v4l.org/pmFlB

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.