Попытка понять оптимизацию array_diff_uassoc

Кажется, что массивы отсортированы, прежде чем сравнивать друг с другом внутри array_diff_uassoc .

В чем преимущество такого подхода?

Тест-скрипт

function compare($a, $b) { echo("$a : $b\n"); return strcmp($a, $b); } $a = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); $b = array('v' => 1, 'w' => 2, 'x' => 3, 'y' => 4, 'z' => 5); var_dump(array_diff_uassoc($a, $b, 'compare')); $a = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); $b = array('d' => 1, 'e' => 2, 'f' => 3, 'g' => 4, 'h' => 5); var_dump(array_diff_uassoc($a, $b, 'compare')); $a = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); $b = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); var_dump(array_diff_uassoc($a, $b, 'compare')); $a = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5); $b = array('e' => 5, 'd' => 4, 'c' => 3, 'b' => 2, 'a' => 1); var_dump(array_diff_uassoc($a, $b, 'compare')); 

http://3v4l.org/DKgms#v526

PS кажется, что алгоритм сортировки изменился в php7.

Алгоритм сортировки не изменился в PHP 7. Элементы просто передаются в другом порядке алгоритму сортировки для некоторых улучшений производительности.

Ну, преимущество может быть в конечном счете быстрее. Вы действительно попадаете в худший случай, когда у обоих массивов есть другие ключи.

Худшая сложность случая состоит в том, чтобы дважды сортировать массивы, а затем сравнивать каждый ключ из двух массивов. O(n*m + n * log(n) + m * log(m))

Лучший случай – это дважды сортировка, а затем столько же сравнений, сколько элементов в меньшем массиве. O(min(m, n) + n * log(n) + m * log(m))

В случае совпадения вам больше не придется сравнивать с полным массивом, но только с ключа после матча.

Но в текущей реализации сортировка просто избыточна. Я думаю, что реализация в php-src нуждается в улучшении. Там нет прямой ошибки, но реализация просто плохая. Если вы понимаете некоторый C: http://lxr.php.net/xref/PHP_TRUNK/ext/standard/array.c#php_array_diff (обратите внимание, что эта функция вызывается через php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER); из array_diff_uassoc )

теория

Сортировка позволяет сделать несколько ярлыков; например:

 A | B -------+------ 1,2,3 | 4,5,6 

Каждый элемент A будет сравниваться только с B [0], поскольку другие элементы, как известно, по меньшей мере такие же большие.

Другой пример:

 A | B -------+------- 4,5,6 | 1,2,6 

В этом случае A [0] сравнивается со всеми элементами B, но A [1] и A [2] сравниваются только с B [2].

Если какой-либо элемент A больше всех элементов в B, вы получите наихудшую производительность.

практика

Хотя выше это хорошо работает для стандартных array_diff() или array_udiff() , как только используется функция сравнения ключей, она будет использовать производительность O (n * m) из-за этого изменения , пытаясь исправить эту ошибку .

Вышеупомянутая ошибка описывает, как пользовательские функции сравнения ключей могут вызывать неожиданные результаты при использовании с массивами, которые имеют смешанные ключи (то есть числовые и строковые значения ключа). Я лично считаю, что это должно было быть рассмотрено с помощью документации, потому что вы получите одинаково странные результаты с помощью ksort() .