在平面数组中的所有键前面添加字符串的最快方法是什么?
输入
$array = array(
'1' => 'val1',
'2' => 'val2',
);
需要输出:
$array = array(
'prefix1' => 'val1',
'prefix2' => 'val2',
);
我想可以排成一长串:
$prefix = "prefix";
$array = array_combine(
array_map(
function($k) use ($prefix) {return $prefix . $k; },
array_keys($array)
),
$array
);
或者 - 正如 Sabrina 在他们的回答中指出的那样 - 使用 php7.4+ 中提供的箭头函数语法。
可能有很多方法可以做到这一点:
$prefix = "prefix";
foreach ($array as $k => $v)
{
$array[$prefix . $k] = $v;
unset($array[$k]);
}
$prefix = "prefix";
$array = KeyPrefixer::prefix($array, $prefix);
class KeyPrefixer
{
private $prefix;
public function __construct($prefix) {
$this->prefix = (string)$prefix;
}
public static function prefix(array $array, $prefix)
{
$prefixer = new KeyPrefixer($prefix);
return $prefixer->mapArray($array);
}
public function mapArray(array $array)
{
return array_combine(
array_map(array($this, 'mapKey', array_keys($array)),
$array
);
}
public function mapKey($key) {
return $this->prefix . (string)$key;
}
}
最初没有 $prefix
作为参数,并且调用了
create_function()
,由于本方脚射门潜力较高,因此不应使用。仅供参考:
$array = array_combine(
array_map(create_function('$k', 'return "prefix$k";'), array_keys($array)),
$array
);
直接与箭头功能比较:
$array = array_combine(
array_map(fn($k) => "prefix$k", array_keys($array)),
$array
);
for(....);
感兴趣,否则它不会正确显示哪种语法更快。我整理了一个简单的基准来表明,当您在迭代期间同时使用键和值时,foreach 实际上是最快的。强制 PHP 从循环迭代中读取值非常重要,否则它会尽力优化它们。在下面的示例中,我使用
doNothing
函数强制 PHP 每次计算键和值。使用 doNothing 会导致每个循环产生开销,但每个循环的开销都是相同的,因为调用次数是相同的。我对
foreach
名列前茅并不感到惊讶,因为它是用于迭代字典的语言构造。
$array = range( 0, 1000000 );
function doNothing( $value, $key ) {;}
$t1_start = microtime(true);
foreach( $array as $key => $value ) {
doNothing( $value, $key );
}
$t1_end = microtime(true);
$t2_start = microtime(true);
$array_size = count( $array );
for( $key = 0; $key < $array_size; $key++ ) {
doNothing( $array[$key], $key );
}
$t2_end = microtime(true);
//suggestion from PHPBench as the "fastest" way to iterate an array
$t3_start = microtime(true);
$key = array_keys($array);
$size = sizeOf($key);
for( $i=0; $i < $size; $i++ ) {
doNothing( $key[$i], $array[$key[$i]] );
}
$t3_end = microtime(true);
$t4_start = microtime(true);
array_walk( $array, "doNothing" );
$t4_end = microtime(true);
print
"Test 1 ".($t1_end - $t1_start)."\n". //Test 1 0.342370986938
"Test 2 ".($t2_end - $t2_start)."\n". //Test 2 0.369848966599
"Test 3 ".($t3_end - $t3_start)."\n". //Test 3 0.78616809845
"Test 4 ".($t4_end - $t4_start)."\n"; //Test 4 0.542922019958
编辑:我在 64 位 Mac OSX 10.6 上使用 PHP 5.3
function keyprefix($keyprefix, Array $array) {
foreach($array as $k=>$v){
$array[$keyprefix.$k] = $v;
unset($array[$k]);
}
return $array;
}
使用
array_flip
不会保留空值或 null 值。 万一前缀键已经存在,可以添加额外的代码。
@Lode 的第一个片段的另一种方法:
function prefixArrayKeys($array, $prefix) {
return array_combine(
array_map(fn($k) => $prefix . $k, array_keys($array)),
$array
);
}
测试:
function testPrefixArrayKeys() {
// Test case 1
$array = ['name' => 'John', 'age' => 30];
assert(prefixArrayKeys($array, 'prefix_') == ['prefix_name' => 'John', 'prefix_age' => 30]);
// Test case 2
$array = ['city' => 'New York'];
assert(prefixArrayKeys($array, '') == ['city' => 'New York']);
// Test case 3
$array = [];
assert(prefixArrayKeys($array, 'prefix_') == []);
// Test case 4
$array = [1 => 'One', 2 => 'Two'];
assert(prefixArrayKeys($array, 'prefix_') == ['prefix_1' => 'One', 'prefix_2' => 'Two']);
echo 'All test cases passed!';
}
// function called by array_walk to change the $value in $key=>$value.
function myfunction(&$value,$key) {
$value="prefix$value";
}
$keys = array_keys($array); // extract just the keys.
array_walk($keys,"myfunction"); // modify each key by adding a prefix.
$a = array_combine($keys,array_values($array)); // combine new keys with old values.
我认为这不会比
for
循环更有效。我猜 array_walk 将在内部使用循环,并且这里还有函数调用开销。
function array_key_prefix_suffix(&$array,$prefix='',$suffix=''){
$key_array = array_keys($array);
$key_string = $prefix.implode($suffix.','.$prefix,$key_array).$suffix;
$key_array = explode(',', $key_string);
$array = array_combine($key_array, $array);
}
这已实施并且运行良好
<?php
$data = array_flip($data);
foreach($data as $key => &$val) { $val = "prefix" . $val; }
$data = array_flip($data);
$prefixed_array = array();
foreach ($array as $key => $value) {
$prefixed_array[ $prefix . $key] = $value;
}
如果你想做任何其他“附加”的
function array_affix_keys($affix, Array $array, $type = 'prefix', $options = array()){
$affixed_array = array();
if($type =='prefix'){
foreach ($array as $key => $value) {$affixed_array[ $affix . $key] = $value;}
return $affixed_array;
}
if($type =='suffix'){
foreach ($array as $key => $value) {$affixed_array[$key . $affix ] = $value;}
return $affixed_array;
}
if($type =='circumfix'){
if(is_array($affix) && count($affix) == 2){
foreach ($array as $key => $value) {
$affixed_array[ $affix[0] . $key . $affix[1] ] = $value;
}
}
return $affixed_array;
}
if($type == 'simulfix' && isset($options['phonemes'])){
foreach ($array as $key => $value) { $affixed_array[ str_replace($options['phonemes'], $affix, $key) ] = $value;}
return $affixed_array;
}
return $array;
}
$prefixed = array_affix_keys('prefix_', $array);
$prefixed = array_affix_keys('prefix_', $array, 'prefix');
$suffixed = array_affix_keys('_suffix', $array, 'suffix');
$circumfixed = array_affix_keys(array('prefix', 'suffix'), $array, 'circumfix');
$simulfix = array_affix_keys('replace', $array, 'simulfix', array('phonemes' => 'find'));
$array = range(0, 1000000);
$delimiter = '-';
$prefix = 'string';
$suffix = '';
$result = array_combine(explode($delimiter, $prefix . implode($suffix . $delimiter . $prefix, array_keys($array)) . $suffix), $array);
substr_replace()
内部使用
array_combine()
(稍微)优于
foreach()
。这将是我首选的数组键前缀!它可能不直观,但它很简洁,具有函数式风格,不声明临时变量或结果变量,并且没有迭代的用户定义函数。 (查看不同版本的完整测试结果)
function substrReplaceAndCombinePrefix($array, $prefix = 'prefix') {
return array_combine(
substr_replace(array_keys($array), $prefix, 0, 0),
$array
);
}
毫不奇怪的是,经典的
foreach()
循环是表现最好的。它也恰好是最简洁的脚本。如果您的代码样式偏好不需要函数语法,那么这可能是最好的方法。也就是说,如果您的输入量非常大,并且性能是高优先级,那么对实际数据进行基准测试将是一个好主意。令人惊讶的是(无论如何对我来说),调用三个特定的本机函数(
array_combine()
,
array_map()
,
array_keys()
)可以优于两个特定的本机函数(
array_reduce()
,
array_keys()
)甚至一个本机函数(
array_walk()
)!
array_walk()
的速度并不慢得可怕,但
array_reduce()
的性能受到严重拖累。以下基准是对具有 5000 个元素的数组调用该技术 20 次的平均值。 (
基准脚本)
foreach()
:(PHP8.2.5执行时间:0.36159753799438)
$result = [];
foreach ($array as $k => $v) {
$result[$prefix . $k] = $v;
}
array_combine()
,
array_map()
,
array_keys()
:(PHP8.2.5执行时间:0.52124261856079)
$result = array_combine(
array_map(
fn($k) => $prefix . $k,
array_keys($array)
),
$array
);
array_walk()
:(PHP8.2.5执行时间:0.77606439590454)
$result = [];
array_walk(
$array,
function($v, $k, $prefix) use (&$result) {
$result[$prefix . $k] = $v;
},
$prefix
);
array_reduce()
,
array_keys()
: (PHP8.2.5 执行时间:49.715828895569)
$result = array_reduce(
array_keys($array),
function($res, $k) use ($array, $prefix) {
$res[$prefix . $k] = $array[$k];
return $res;
},
[]
);
将箭头函数语法与 array_reduce()
一起使用似乎不会提高性能。
$result = array_reduce(
array_keys($array),
fn($result, $k) => $result + [$prefix . $k => $array[$k]],
[]
);
0.58324337005615)
function generator($array, $prefix) {
foreach ($array as $k => $v) {
yield $prefix . $k => $v;
}
}
$result = iterator_to_array(generator($array, $prefix));
array_walk($array, create_function('$value, &$key', '$key = "prefix" . $key;'));