Как правильно увеличить некоторый ключ массива, даже если ключ необходимо создать?
Предположим, вам нужно создать какую-то "вершину" и иметь такой код:
$matches=array();
foreach ($array as $v){
$matches[processing($v)]++;
}
Это выведет Notice: Undefined index
для случаев, когда необходимо создать индекс.
Каков был бы наилучший способ решения этих проблем, поскольку вы ЗНАЕТЕ, что вам придется создавать индексы?
Я использовал эти решения в зависимости от случая:
- Подавление ошибки
@$matches[$v]++;
Pro: ОЧЕНЬ легко вводить
Кон: медленно - Проверка, установлен ли он
$matches[$v]=isset($matches[$v])?$matches[$v]++:1;
Pro: быстрее
Con: требуется больше времени для записи даже в сокращенной форме, и необходимо использовать $matches[$v] еще 2 раза
Есть ли другие способы?
Ищу самое быстрое время выполнения, так как я использую эту функцию тысячи раз или какой-нибудь более ленивый способ ввода , который все равно быстрее, чем @
РЕДАКТИРОВАТЬ:
В простом случае, когда у вас есть $matches[$v]++;
, вы также можете использовать array_count_values()
( как Йоши предложенный)
3 answers
После некоторого чтения, написания и тестирования я получил кое-что:
function inc(&$var){
if (isset($var)) $var++;else $var=1;
}
И подумал, что я нашел золото, но давайте сначала посмотрим тесты...
Тестовый код:
$a=array();
// Pre-Fill array code goes here
for($i=1;$i<100000;$i++) {
$r=rand(1,30000);
//increment code goes here
}
// Remove extra keys from array with:
//foreach ($a as $k=>$v) if ($v==0) unset($a[$k]);
Время выполнения: (только в информационных целях)
inc($a[$r]) 1.15-1.24
@$a[$r]++ 1.03-1.09
$a[$r]=array_key_exists($r,$a)?$a[$r]++:1; 0.99-1.04
$a[$r]=!empty($a[$r])?$a[$r]++:1; 0.61-0.74
if (!empty($a[$r])) $a[$r]++;else $a[$r]=1; 0.59-0.67
$a[$r]=isset($a[$r])?$a[$r]++:1; 0.57-0.65
if (isset($a[$r])) $a[$r]++;else $a[$r]=1; 0.56-0.64
//with pre-fill
$a=array_fill(0,30000,0); +0.07(avg)
for($i=1;$i<=30000;$a[$i++]=0); -0.04(avg)
//with pre-fill and unset
$a=array_fill(0,45000,0); +0.16(avg)
for($i=1;$i<=45000;$a[$i++]=0); +0.02(avg)
Выводы:
-
@
, конечно, самый быстрый для ввода, и я не вижу никаких проблем в его использовании в данном случае, но не стесняйтесь также проверять этот вопрос: Подавлять ошибку с помощью оператора @ в PHP - полное подавление ошибок (до цикла и включение ошибок после цикла) с помощью
ini_set()
хуже всего сказывается на производительности -
inc()
выглядит красиво и чисто, легко набирается и выполняет проверку вместо подавления, но вызов выглядит еще медленнее, чем@
-
isset()
немного быстрее, чемempty()
, но оба работают примерно одинаково - интересно использовать стенографию
if
операторы немного медленнее! - лучший результаты, достигнутые при предварительном заполнении массива. Даже если длина неизвестна, хороший прогноз все равно будет немного быстрее для огромного набора данных
- как ни странно,
array_fill()
занимает немного больше времени, чемfor
?!?!
RFC
Я не считаю этот ответ на 100% полным, хотя на данный момент он выглядит как isset()
самый быстрый и @
самый ленивый.
Любые комментарии и идеи приветствуются!
Возможно, вы могли бы инициализировать массив совпадений для начала, используя array_combine
для объединения значений из $array
в качестве ключей и array_fill
для заполнения значений начальным 0
$matches = array_combine(array_values($array), array_fill(0, count($array), 0));
Я всегда делаю:
$matches=array();
foreach ($matches as $v){
/* if $v is not empty, add 1, otherwise $v= 1 */
$matches[$v]=(!(empty($matches[$v]))) ? $matches[$v]++ : 1;
}
Ты прав. Это немного многословно, но, честно говоря, в то же время довольно лаконично. Хотя я использую empty()
вместо isset()
. Не уверен, что это быстрее или медленнее у меня в голове. Я думаю, что это, вероятно, медленнее.
Редактировать
Чтобы ответить на ваше редактирование, я бы сделал это так:
$matches=array();
foreach ($matches as $v){
$x=function($v);
/* if $v is not empty, add 1, otherwise $v= 1 */
$matches[$x]=(!(empty($matches[$x]))) ? $matches[$x]++ : 1;
}
Таким образом, вы вызываете функцию только один раз.