2010-04-09 2 views

ответ

10

Я обнаружил, что 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 

Edit: Я использую PHP 5.3 на 64-разрядные Mac OSX 10.6

+0

Это немного странно, потому что я получаю значения в 10 раз ниже: '0.043029069900513'. Вы знаете, почему это может произойти? Это PHP 5.4.3. И если я запустил это только для одного «foreach», а не для моего более длинного скрипта, то это: «6.4849853515625E-5' – Atadj

+0

Они, кажется, находятся в правом фойе для меня: http: //codepad.viper-7. ком/b1gHRC. Foreach все еще остается явным победителем. –

+0

Да, foreach - победитель, но мне интересно, почему этот сайт показывает «0.0497624» и мой сайт, с точно таким же сценарием показывает «0.0000871». – Atadj

2

Если вы не хотите использовать для цикла вы можете сделать:

// 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 будет внутренне использовать цикл, и здесь также есть служебные вызовы функции.

+0

во время работы, что невероятно медленно по сравнению с для петля не так ли? – Gordon

+0

Нельзя использовать по ссылке. Это на самом деле медленнее и интенсивнее, чем просто передавать и возвращать его. Не могу найти docs реального быстрого atm. – Martijn

43

Могли бы сделать это в одну длинную строку, я полагаю:

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

Не нужно устанавливать 'array_values ​​()' для 'array_map()' как 2-го аргумента. Если вы просто выбросите массив, он будет использовать значение в любом случае. – kaiser

-1

я понял, решение одной строки:

array_walk($array, create_function('$value, &$key', '$key = "prefix" . $key;')); 
+1

Это не работает. Клавиши не меняются. Это то же самое, что я пытался сделать в течение большей части часа: http://codepad.org/h88Is8ug – Travesty3

+1

не работает, ключи не могут быть изменены array_walk следующим образом – chim

1

Другой способ сделать достижения является с array_flip()

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

довольно творческий. – r3wt

+0

Плохая опция, если у вас одинаковые значения в массиве – Anton

3
function keyprefix($keyprefix, Array $array) { 

    foreach($array as $k=>$v){ 
     $array[$keyprefix.$k] = $v; 
     unset($array[$k]); 
    } 

    return $array; 
} 

Использование array_flip не сохранит пустые или нулевые значения , Дополнительный код может быть добавлен в маловероятном случае, когда ключ с префиксом уже существует.

+0

прост и работает отлично –

0

Я бы создал совершенно новый массив и создал новые ключи. Это должно быть быстрее, чем снятие всех нежелательных ключей;

$prefixed_array = array(); 

foreach ($array as $key => $value) { 
    $prefixed_array[ $prefix . $key] = $value; 
} 

И если вы хотите сделать какой-либо другой «наклеить» 's

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

Эта реализация 'circumfix' неверна. Circumfix имеет другое окончание, чем начало, например. 'За (...) kan'. [Wiki] (https://en.wikipedia.org/wiki/Circumfix) – simivar

+0

хорошо заметили спасибо – TarranJones

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

Это реализовано и работает очень хорошо

Смежные вопросы