Поведение array_diff_uassoc не ясно - PullRequest
5 голосов
/ 27 февраля 2012

Прежде всего, я должен упомянуть, что я копался в руководствах и документах php и не нашел ответа. Вот код, который я использую:

class chomik {

    public $state = 'normal';
    public $name = 'no name';

    public function __construct($name) {
        $this->name = $name;
    }

    public function __toString() {
        return $this->name . " - " . $this->state;
    }
}

function compare($a, $b) {
    echo("$a : $b<br/>");
    if($a != $b) {
        return 0;
    }
    else return 1;
}

$chomik = new chomik('a');
$a = array(5, $chomik, $chomik, $chomik);
$b = array($chomik, 'b', 'c', 'd');
array_diff_uassoc($a, $b, 'compare');

Как я и думал, array_diff_uassoc будет сравнивать все значения этих двух массивов, а если значения существуют, то будет выполняться сравнение ключей. И вывод этого кода:

1 : 0
3 : 1
2 : 1
3 : 2
1 : 0
3 : 1
2 : 1
3 : 2
3 : 3
3 : 2
2 : 3
1 : 3
0 : 3

Итак, прежде всего, почему некоторые пары (1: 0 или 3: 1) дублируются? Значит ли это, что функция забыла, что она уже сравнивала эти элементы? Я думал, что он будет сравнивать все пары по значению, но я не вижу его в выводе. Я что-то упустил?

Итак, вопрос: каково точное поведение этой функции с точки зрения порядка сравнения, и почему я вижу это дубликаты? (моя версия PHP, если это поможет: версия PHP 5.3.6-13ubuntu3.6)

Я действительно запутался и жду хорошего объяснения ...

Ответы [ 3 ]

0 голосов
/ 02 апреля 2015

Я думаю, что вы пропустили раздел возвращаемого значения.

Возвращает массив, содержащий все записи из массива1, которых нет ни в одном из других массивов.

ключи массива используются в сравнении.

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

То же самое с

$one = array(a,b,c,'hot'=>d); // d has no match and  will be returned as array and go to the function alone
$two = array(a,b,c,d,e,f); //

Поскольку $ one hot => d не совпадает с $ two 0 => d на ассоциативном уровне, возвращается $ one hot => d.

Из-за особенностей PHP для сравнения строковых и целочисленных типов данных пользовательская функция может быть использована для улучшения сравнения с помощью более сильных операций сравнения, таких как ===.

Это помогает в ситуациях, когда тип неоднозначен'0' => d и 0 => d могут выглядеть одинаково, но это не так, пока вы не скажете это в своем коде.

К счастью, подсказка типа приходит в PHP7, чтобы избавить нас от этого типа странной конструкции и неясной документации.

Я добавляю это из моего комментария, потому что это относится к вашему пониманию того, какие конструкции php являютсялучше всего использовать в вашем случае.Мой комментарий:

Я не очень уверен в этом, так как если ($ a! = $ B) {в их коде является проблемой.Поскольку они по ошибке используют равенство, когда они должны использовать идентичные операторы! ==.И они используют числовые ключи в конструкции, предназначенной для ассоциативных ключей.они, вероятно, также не знают о array_udiff, который лучше подходит для данных

0 голосов
/ 03 апреля 2015

Это действительно несколько интригующе.Я посмотрел последний источник PHP на github (который написан на C ++, как вы, наверное, знаете) и попытался разобраться в этом.(https://github.com/php/php-src/blob/master/ext/standard/array.c)

Быстрый поиск показал, что рассматриваемая функция объявлена ​​в строке 4308

PHP_FUNCTION(array_diff_uassoc)
{
    php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
}

Так что это показывает, что фактическая работа выполняется функцией php_array_diff,это можно найти в том же файле в строке 3938. Вставить его сюда немного длиннее, если быть точным, 265 строк, но вы можете посмотреть его, если хотите.

Именно здесь я и далЯ не имею никакого опыта в C, и это слишком поздно, и я устал, чтобы попытаться разобраться в этом. Я полагаю, сначала выполняется сравнение ключей, так как оно, вероятно, более производительно, чем сравнение значений, но этоэто всего лишь предположение. В любом случае, вероятно, есть веская причина, почему они делают это так, как они делают.

Все, что нужно, это длинное вступление, чтобы сказать: зачем вам ставить * 1013?* внутри вашей compare функции в первую очередь ? Целью array_diff_uassoc является вывод функции. Вы не должны полагаться на то, как парсер обрабатывает ее. Если они решат завтра изменить внутреннюю работу этогоC funcт. е.сначала сделайте сравнение значений, вы получите совершенно другой результат.

Возможно, вы могли бы использовать эту функцию замены, написанную на php: http://pear.php.net/reference/PHP_Compat-1.6.0a2/__filesource/fsource_PHP_Compat__PHP_Compat-1.6.0a2CompatFunctionarray_diff_uassoc.php.html

Таким образом, вы можете полагайтесь на то, что поведение не меняется, и вы полностью контролируете внутреннюю работу ...

0 голосов
/ 02 апреля 2015

из оп комментарий , что

Мне нужны только те элементы, которых нет во втором массиве ($ a [0])

вы не можете использовать array_diff($a, $b);? возвращается

array(1) {
  [0]=>
  int(5)
}

в противном случае

В документации указано, что:

Функция сравнения должна возвращать целое число меньше, равно или больше нуля, если первый аргумент считается равным соответственно меньше, равно или больше второго.

Насколько я понимаю, это означает, что функция compare() должна выглядеть примерно так:

function compare($a, $b) {
    echo("$a : $b<br/>");
    if($a === $b) return 0;
    else if ($a > $b) return 1;
    else return -1;
}

Однако даже с этой поправкой результаты сравнения очень странные:

1 : 0
1 : 2
3 : 1
2 : 1
3 : 2
1 : 0
1 : 2
3 : 1
2 : 1
3 : 2
0 : 0
1 : 0
1 : 1
2 : 0
2 : 1
2 : 2
3 : 0
3 : 1
3 : 2
3 : 3

Я задал еще один вопрос об этом, когда он выходил за рамки ответа.

...