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_walk和array_map函数实现数组值UTF-8转GBK编码
如何在 PHP 中使用带有 array_map(...) 的数组?