Каков самый быстрый способ добавить строковые префиксы к клавишам массива?
вход
$array = array( '1' => 'val1', '2' => 'val2', );
Требуемый результат:
$array = array( 'prefix1' => 'val1', 'prefix2' => 'val2', );
Я обнаружил, что 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
Изменить: я использую PHP 5.3 на 64-разрядной Mac OSX 10.6
Мог бы сделать это в одной длинной строке, я полагаю:
$array = array_combine( array_map(function($k){ return 'prefix'.$k; }, array_keys($array)), $array );
Или для версий PHP до 5.3:
$array = array_combine( array_map(create_function('$k', 'return "prefix".$k;'), array_keys($array)), $array );
Есть, вероятно, десятки способов сделать это, хотя:
foreach ($array as $k => $v) { $array['prefix_'.$k] = $v; unset($array[$k]); }
сforeach ($array as $k => $v) { $array['prefix_'.$k] = $v; unset($array[$k]); }
function keyprefix($keyprefix, Array $array) { foreach($array as $k=>$v){ $array[$keyprefix.$k] = $v; unset($array[$k]); } return $array; }
сfunction keyprefix($keyprefix, Array $array) { foreach($array as $k=>$v){ $array[$keyprefix.$k] = $v; unset($array[$k]); } return $array; }
Использование array_flip
не будет сохранять пустые или нулевые значения. Дополнительный код может быть добавлен в маловероятном случае, когда ключ с префиксом уже существует.
Если вы не хотите использовать цикл 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 будет внутренне использовать цикл, и здесь также есть служебные вызовы функции.
Еще один способ добиться этого – с помощью array_flip ()
<?php $data = array_flip($data); foreach($data as $key => &$val) { $val = "prefix" . $val; } $data = array_flip($data);
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); }
Это реализовано и работает очень хорошо
Я бы создал совершенно новый массив и создал новые ключи. Это должно быть быстрее, чем устранение всех нежелательных ключей;
$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_walk($array, create_function('$value, &$key', '$key = "prefix" . $key;'));