PHP: Tôi có thể lấy chỉ mục trong một hàm array_map không?


83

Tôi đang sử dụng một bản đồ trong php như vậy:

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

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

Có thể lấy chỉ số của giá trị trong hàm không?

Ngoài ra - nếu tôi đang viết mã cần chỉ mục, tôi có nên sử dụng vòng lặp for thay vì bản đồ không?

Câu trả lời:


209

Chắc chắn bạn có thể, với sự giúp đỡ của 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
Câu trả lời tuyệt vời, không nhận ra rằng bạn có thể truyền thêm các tham số vào phương thức array_map () ped. Học điều mới mỗi ngày!
GordonM

1
@Gordon vâng, bạn có thể cung cấp array_map()với số lượng đối số tùy ý :)
Aron Rotteveel

13
Đây là một cách tiếp cận rất rủi ro vì PHP không đảm bảo rằng các khóa được trả về array_keyssẽ vẫn theo thứ tự như trong mảng ban đầu. Vì vậy, bạn có thể kết thúc ánh xạ khóa đến các giá trị sai. Cách tiếp cận an toàn là chỉ sử dụng array_keyslàm đối số thứ hai của array_mapvà sau đó truyền mảng để đóng với usecâu lệnh.
user487772

12
Thành thật mà nói, tôi không hiểu tại sao PHP không có hàm bản đồ cung cấp khóa của mỗi phần tử làm tham số thứ hai của lệnh gọi lại.
cúm

1
@flu PHP không đạt danh hiệu ngôn ngữ xấu mà không có lý do.
xZero

9

Khi ánh xạ một hàm ẩn danh qua một mảng ẩn danh, không có cách nào để truy cập các khóa:

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

array_reduce cũng không có quyền truy cập vào các khóa. array_walk có thể truy cập các khóa, nhưng mảng được truyền bởi tham chiếu, điều này yêu cầu một lớp hướng dẫn.

Một số giải pháp là:

Mảng các cặp

Điều này thật tệ, vì chúng tôi đang thay đổi mảng ban đầu. Cộng với các lệnh gọi "array ()" của bảng soạn sẵn sẽ tăng tuyến tính với độ dài của mảng:

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

Biến tạm thời

Chúng tôi đang hành động trên mảng ban đầu và bảng soạn sẵn là không đổi, nhưng chúng tôi có thể dễ dàng chặn một biến hiện có:

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

Chức năng chụp một lần

Chúng tôi có thể sử dụng phạm vi chức năng để ngăn chặn các tên hiện có, nhưng phải thêm một lớp bổ sung "sử dụng":

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

Chức năng một lần nhiều đối số

Chúng tôi xác định chức năng mà chúng tôi đang ánh xạ trong phạm vi ban đầu để ngăn chặn bảng soạn sẵn "sử dụng"):

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

Chức năng mới

Điều thú vị cần lưu ý là hàm one-shot cuối cùng của chúng ta có một chữ ký chung, đẹp và trông rất giống với array_map. Chúng tôi có thể muốn đặt tên này và sử dụng lại nó:

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

Mã ứng dụng của chúng tôi sau đó trở thành:

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

Đi bộ theo mảng gián tiếp

Khi viết phần trên, tôi đã bỏ qua array_walk vì nó yêu cầu đối số của nó phải được truyền bằng tham chiếu; tuy nhiên, tôi đã nhận ra rằng thật dễ dàng để giải quyết vấn đề này bằng cách sử dụng call_user_func. Tôi nghĩ đây là phiên bản tốt nhất cho đến nay:

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

0

Rất đơn giản:

Chỉ array_map fuction: không có khóa chỉ mục!

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

Bây giờ, hãy kết hợp với 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)
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.