PHP:我可以在 array_map 函数中获取索引吗?

Posted

技术标签:

【中文标题】PHP:我可以在 array_map 函数中获取索引吗?【英文标题】:PHP: Can I get the index in an array_map function? 【发布时间】:2011-08-17 15:05:39 【问题描述】:

我在 php 中使用这样的地图:

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


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

是否可以在函数中获取值的索引?

另外 - 如果我正在编写需要索引的代码,我应该使用 for 循环而不是映射吗?

【问题讨论】:

【参考方案1】:

当然可以,在 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);

【讨论】:

很酷的答案,没有意识到您可以将额外的参数传递给 array_map()ped 方法。每天学习新东西! 这是一种非常危险的方法,因为 PHP 不保证 array_keys 返回的键将保持与原始数组中相同的顺序。因此,您最终可能会将键映射到错误的值。安全的方法是只使用array_keys 作为array_map 的第二个参数,然后使用use 语句将数组传递给闭包。 老实说我不明白为什么 PHP 没有一个 map 函数来提供每个元素的键作为回调的第二个参数。 @flu PHP 没有无缘无故没有获得糟糕语言的称号。 我同意在这种情况下最好不要使用array_keys。相反,我们可以使用 range(0, count($array)-1) 获取索引【参考方案2】:

将匿名函数映射到匿名数组时,无法访问键:

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

一次性功能

我们可以使用函数范围来防止破坏现有名称,但必须添加一个额外的“使用”层:

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

【讨论】:

【参考方案3】:

很简单:

只有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)

【讨论】:

【参考方案4】:

您可以使用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

【讨论】:

【参考方案5】:

对于一个快速和开放的解决方案(不使用 array_keys 和类似的加倍数组):

/**
 * Array map alternative to work with values and keys of single array.
 *
 * Callable receives $value and $index of $sourceArray as arguments
 * If keys are not preserved via $preserveKeys - $keyCallback can be used to determinate key
 *
 * @param array $sourceArray
 * @param callable|null $valueCallback
 * @param callable|null $keyCallback
 * @param bool $preserveKeys
 * @return array
 */
function array_map_indexed(
    array $sourceArray,
    ?callable $valueCallback = null,
    ?callable $keyCallback = null,
    bool $preserveKeys = true
): array 
    $newArray = [];

    foreach ($sourceArray as $key => $value) 
        if ($preserveKeys) 
            $newArray[$keyCallback ? $keyCallback($value, $key) : $key] = $valueCallback
                ? $valueCallback($value, $key)
                : $value;
         else 
            $newArray[] = $valueCallback
                ? $valueCallback($value, $key)
                : $value;
        
    

    return $newArray;

用法示例:

$result = array_map_indexed(
    [
        'a' => 'aValue',
        'b' => 'bValue',
    ],
    function($value, $index) 
        return [$value, $index];
    ,
);
//Array ( [a] => Array ( [0] => aValue [1] => a ) [b] => Array ( [0] => bValue [1] => b ) )

$result = array_map_indexed(
    [
        'a' => 'aValue',
        'b' => 'bValue',
    ],
    function($value, $index) 
        return $index.$value;
    ,
    null,
    false
);
//Array ( [0] => aaValue [1] => bbValue )

$result = array_map_indexed(
    [
        'a' => 'aValue',
        'b' => 'bValue',
    ],
    null,
    function($value, $index) 
        return $value === 'aValue' ? 'specificKey' : $index;
    ,
);
//Array ( [specificKey] => aValue [b] => bValue )

【讨论】:

【参考方案6】:

无法在array_map 回调中访问索引。如果您正在使用顺序数字索引,则可以使用递增的静态变量:

$values = ["one", "two", "three"];

$mapped = array_map(function ($value) 
    static $i = 0;
    $result = "Index: $i, Value: $value";
    $i++;
    return $result;
, $values);

print_r($mapped);

导致:

Array
(
    [0] => Index: 0, Value: one
    [1] => Index: 1, Value: two
    [2] => Index: 2, Value: three
)

使用这种方法时,重要的是使用 anonymous function 作为回调,并且永远不要重复使用该匿名函数以避免在 array_map 之外引用相同的静态变量。

【讨论】:

【参考方案7】:

这有点老了,但和你们一样,我正在使用 array_keys :

array_map(function($id, $name) 
    print '<option value="'.$id.'">'.$name.'</option>';
, array_keys($array), array_values($array));

编辑:你可以在你的 array_map 函数的第二个参数中添加两个数组,而不是使用关键字。我觉得不需要解释,代码很简单。

【讨论】:

以上是关于PHP:我可以在 array_map 函数中获取索引吗?的主要内容,如果未能解决你的问题,请参考以下文章

PHP array_map 一个有趣的函数

php array_map与array_walk使用对比

PHP的array_walk和array_map函数实现数组值UTF-8转GBK编码

如何在 PHP 中使用带有 array_map(...) 的数组?

php中array_walk() 和 array_map()两个函数区别

php中array_map和array_walk的使用对比