Многие ответы рекомендуют способ array_map
, а многие более тривиальный for
цикл.
Я думаю, что решение array_map
выглядит лучше и «более продвинуто», чем циклическое выполнение массивов и построениеконкатенированный массив в цикле for
, НО - вопреки моим ожиданиям - он намного медленнее обычного for
.
Я провел несколько тестов с версией PHP 7.1.23-4 на Ubuntu16.04.1: с двумя массивами, каждый из которых содержит 250 тыс. Элементов 10-значных случайных чисел, решение for
заняло 4,7004 с в течение 20 прогонов, в то время как решение array_map
заняло 11,7939 с в течение 20 прогонов на моей машине, почти в 2,5 раза медленнее !!!
Я бы ожидал, что PHP лучше оптимизирует встроенную функцию array_map
, чем цикл for
, но выглядит наоборот:
Код, который я тестировал:
// Init the test
$total_time_for = 0;
$total_time_arraymap = 0;
$array1 = [];
$array2 = [];
for ( $i = 1; $i <= 250000; $i ++ ) {
$array1[] = mt_rand(1000000000,9999999999);
$array2[] = mt_rand(1000000000,9999999999);
}
// Init completed
for ( $j = 1; $j <= 20; $j ++ ) {
// Init for method
$array_new = [];
$startTime = microtime(true);
// Test for method
for ( $i = 0; $i <= count($array1); $i ++ ) {
$array_new[] = $array1[$i] . " " . $array2[$i];
}
// End of test content
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
$total_time_for += $elapsed;
//echo "for - Execution time : $elapsed seconds" . "\n";
unset($array_new);
//----
// Init array_map method
$array_new = [];
$startTime = microtime(true);
// Test array_map method
$array_new = array_map(function($a, $b) { return $a . ' ' . $b; }, $array1, $array2);
// End of test content
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
$total_time_arraymap += $elapsed;
//echo "array_map - Execution time : $elapsed seconds" . "\n";
unset($array_new);
}
echo "for - Total execution time : $total_time_for seconds" . "\n";
echo "array_map - Total execution time : $total_time_arraymap seconds" . "\n";
Возникает вопрос, чем хороша array_map
?Один из возможных ответов, который приходит мне в голову, заключается в том, что если у нас где-то есть предопределенная функция, может быть, в сторонней библиотеке, мы хотели бы применить ее к массивам, и мы не хотим переопределять эту функцию внутри нашего цикла for.array_map
в этом случае представляется удобным применить эту функцию к нашим массивам.Но разве это лучше, чем вызывать функцию из цикла for
?
Я тоже это проверял, и похоже, что array_map
превосходит при использовании предопределенных функций.На этот раз array_map
заняло 8,7176 с, а цикл for
занял 12,8452 с, чтобы выполнить ту же работу, что и выше.
Код, который я тестировал:
// Init the test
$total_time_for = 0;
$total_time_arraymap = 0;
$array1 = [];
$array2 = [];
for ( $i = 1; $i <= 250000; $i ++ ) {
$array1[] = mt_rand(1000000000,9999999999);
$array2[] = mt_rand(1000000000,9999999999);
}
function combine($a, $b) {
return $a . ' ' . $b;
}
// Init completed
for ( $j = 1; $j <= 20; $j ++ ) {
// Init for method
$array_new = [];
$startTime = microtime(true);
// Test for method
for ( $i = 0; $i <= count($array1); $i ++ ) {
$array_new[] = combine($array1[$i], $array2[$i]);
}
// End of test content
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
$total_time_for += $elapsed;
//echo "for external function call - Execution time : $elapsed seconds" . "\n";
unset($array_new);
//----
// Init array_map method
$array_new = [];
$startTime = microtime(true);
// Test array_map method
$array_new = array_map('combine', $array1, $array2);
// End of test content
$endTime = microtime(true);
$elapsed = $endTime - $startTime;
$total_time_arraymap += $elapsed;
//echo "array_map external function call - Execution time : $elapsed seconds" . "\n";
unset($array_new);
}
echo "for external function call - Total execution time : $total_time_for seconds" . "\n";
echo "array_map external function call - Total execution time : $total_time_arraymap seconds" . "\n";
Очень длинная историякороче, общий вывод:
- Вызов предопределенной функции: используйте
array_map
, это занимает ~ 40% меньше времени (8,7 с против 12,8 с) - Реализация массива прямо там, где это необходимо: используйте цикл
for
, это займет ~ 60% меньше времени (4,7 с против 11,8 с). - У вас есть выбор между использованием предопределенной функции или (повторно) реализовать его там, где это необходимо: использовать цикл
for
и выполнить необходимые манипуляции внутри цикла, это займет ~ 45% меньше времени (4,7 с против 8,7 с).
На основании этого, в вашем конкретном сценарии использования , используйте цикл for
и выполните конкатенацию внутри тела цикла, не вызывая другие функции.