PHP: İndeksi bir array_map işlevinde alabilir miyim?


87

PHP'de şu şekilde bir harita kullanıyorum:

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

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

Fonksiyondaki değerin indeksini almak mümkün mü?

Ayrıca - indekse ihtiyaç duyan kod yazıyorsam, harita yerine for döngüsü kullanmalı mıyım?

Yanıtlar:


215

Elbette yapabilirsin, yardımıyla 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
Güzel cevap, fazladan parametreleri bir array_map () ped yöntemine geçirebileceğinizi bilmiyordum. Her gün yeni bir şeyler öğrenin!
GordonM

1
@Gordon evet array_map(), keyfi sayıda argüman
sağlayabilirsiniz

13
PHP, tarafından döndürülen anahtarların array_keysorijinal dizideki ile aynı sırada kalacağını garanti etmediğinden, bu çok riskli bir yaklaşımdır . Bu nedenle, anahtarları yanlış değerlerle eşleştirebilirsiniz. Güvenli yaklaşım, yalnızca array_keysikinci argüman olarak kullanmak array_mapve ardından diziyi useifadeyle kapatmaya iletmektir.
user487772

12
Açıkçası, PHP'nin neden her öğenin anahtarını geri çağırmanın ikinci parametresi olarak sağlayan bir eşleme işlevine sahip olmadığını anlamıyorum.
grip

1
@flu PHP sebepsiz yere kötü dil unvanını kazanmadı.
xZero

9

Anonim bir işlevi anonim bir dizi üzerinde eşlerken, anahtarlara erişmenin bir yolu yoktur:

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

array_reduce, anahtarlara da erişemez. array_walk anahtarlara erişebilir, ancak dizi başvuruya göre aktarılır, bu da bir yönlendirme katmanı gerektirir.

Bazı çözümler şunlardır:

Çift dizisi

Bu kötü, çünkü orijinal diziyi değiştiriyoruz. Ayrıca, standart "dizi ()" çağrıları, dizinin uzunluğu ile doğrusal olarak artar:

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

Geçici değişken

Orijinal diziye göre hareket ediyoruz ve ortak şablon sabittir, ancak mevcut bir değişkeni kolayca bozabiliriz:

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

Tek atış işlevi

Mevcut adların bozulmasını önlemek için işlev kapsamını kullanabiliriz, ancak fazladan bir "kullanım" katmanı eklememiz gerekir:

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

Çok bağımsız değişkenli tek atış işlevi

Orijinal kapsamda eşleştirdiğimiz işlevi, standart şablonun "kullanılmasını" önlemek için tanımlarız:

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

Yeni işlev

Unutulmaması gereken ilginç şey, son tek vuruşluk fonksiyonumuzun güzel, genel bir imzası olması ve çok sayıda array_map'e benzemesi. Buna bir isim verip yeniden kullanmak isteyebiliriz:

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

Uygulama kodumuz şu hale gelir:

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

Dolaylı Dizi Yürüyüşü

Yukarıdakileri yazarken, argümanının referans olarak iletilmesini gerektirdiğinden array_walk'u yok saymıştım; ancak, o zamandan beri call_user_func kullanarak bu sorunu çözmenin kolay olduğunu anladım. Bence bu şimdiye kadarki en iyi versiyon:

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

1

Çok basit:

Yalnızca array_map fuction: dizin anahtarı yoktur!

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

Şimdi, array_keys ile birleştirin:

$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

Aşağıdakileri kullanarak kendi harita işlevinizi oluşturabilirsiniz 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);

deneyin: https://3v4l.org/pmFlB

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.