向所有数组键添加前缀的最快方法?

问题描述 投票:0回答:11

在平面数组中的所有键前面添加字符串的最快方法是什么?

输入

$array = array(
 '1' => 'val1',
 '2' => 'val2',
);

需要输出:

$array = array(
  'prefix1' => 'val1',
  'prefix2' => 'val2',
);
php arrays concatenation key prefix
11个回答
75
投票

我想可以排成一长串:

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


现在历史上适用于 5.3 之前的 PHP 版本:

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

13
投票
我发现 PHPBench 并不是一个非常好的基准测试来源。因此,除非您真的对运行

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


7
投票
function keyprefix($keyprefix, Array $array) { foreach($array as $k=>$v){ $array[$keyprefix.$k] = $v; unset($array[$k]); } return $array; }

使用

array_flip

 不会保留空值或 null 值。
万一前缀键已经存在,可以添加额外的代码。


4
投票
使用 php7.4+ 中提供的箭头函数语法编写

@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!'; }
    

2
投票
如果你不想使用for循环,你可以这样做:

// 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 将在内部使用循环,并且这里还有函数调用开销。


2
投票
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); }

这已实施并且运行良好


0
投票
另一种实现方法是使用 array_flip()

<?php $data = array_flip($data); foreach($data as $key => &$val) { $val = "prefix" . $val; } $data = array_flip($data);
    

0
投票
我将创建一个全新的数组,并创建新的密钥。 这必须比取消所有不需要的键更快;

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

0
投票
这是一种快速的单行解决方案(PHP 4+ 支持),用于使用 implode/explode 添加前缀和/或后缀:

$array = range(0, 1000000); $delimiter = '-'; $prefix = 'string'; $suffix = ''; $result = array_combine(explode($delimiter, $prefix . implode($suffix . $delimiter . $prefix, array_keys($array)) . $suffix), $array);
    

0
投票
2024年3月28日更新:

令我惊讶的是,在我执行的大约一半的测试中,在

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 次的平均值。 (

基准脚本)

  1. foreach()

    :(PHP8.2.5执行时间:
    0.36159753799438

    $result = []; foreach ($array as $k => $v) { $result[$prefix . $k] = $v; }
    
    
  2. array_combine()

    array_map()
    array_keys()
    :(PHP8.2.5执行时间:
    0.52124261856079

    $result = array_combine( array_map( fn($k) => $prefix . $k, array_keys($array) ), $array );
    
    
  3. array_walk()

    :(PHP8.2.5执行时间:
    0.77606439590454

    $result = []; array_walk( $array, function($v, $k, $prefix) use (&$result) { $result[$prefix . $k] = $v; }, $prefix );
    
    
  4. 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]], [] );
    
    
  5. 生成器:(PHP8.2.5执行时间:

    0.58324337005615

    function generator($array, $prefix) { foreach ($array as $k => $v) { yield $prefix . $k => $v; } } $result = iterator_to_array(generator($array, $prefix));
    
    

-1
投票
我想出了一行解决方案:

array_walk($array, create_function('$value, &$key', '$key = "prefix" . $key;'));
    
© www.soinside.com 2019 - 2024. All rights reserved.