Welcome! Log In Create A New Profile

Advanced

[PHP] Should array_udiff be comparing elements from the same array?

Posted by Richard Quadling 
Richard Quadling
[PHP] Should array_udiff be comparing elements from the same array?
November 10, 2017 02:00PM
Hi.

Was testing array_udiff against some complex behaviour. Had an oddity.
Reduced the code to a simple test ...

3v4l.org/XON0v

<?php

$array1 = array(1, 2, 3);
$array2 = array(3, 4, 5);

print_r(
array_udiff(
$array1,
$array2,
function ($a, $b) {
static $tests = 0;
echo 'array_udiff ', ++$tests, ' ', $a, ' vs ', $b, PHP_EOL;

return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
}
)
);


The output is :

array_udiff 1 1 vs 2 array_udiff 2 2 vs 3 array_udiff 3 3 vs 4 array_udiff
4 4 vs 5 array_udiff 5 1 vs 3 array_udiff 6 1 vs 2 array_udiff 7 2 vs 3
array_udiff 8 2 vs 3 array_udiff 9 3 vs 3 Array ( [0] => 1 [1] => 2 )


Tests 1 and 4 suggests that elements from with a single array are being
compared. Is this expected behaviour?

This seems wrong when you use a nested array and each set uses a different
key name.

For example.

<?php

$array1 = array(array('A' => 1), array('A' => 2), array('A' => 3));
$array2 = array(array('B' => 3), array('B' => 4), array('B' => 5));

print_r(
array_udiff(
$array1,
$array2,
function ($a, $b) {
static $tests = 0;
echo 'array_udiff ', ++$tests, ' ', $a['A'], ' vs ',
$b['B'], PHP_EOL;

return ($a['A'] < $b['B']) ? -1 : (($a['A'] > $b['B']) ? 1 : 0);
}
)
);

With this, you now get errors.

array_udiff 1 array (
'A' => 1,
) vs array (
'A' => 2,
)

Notice: Undefined index: B in
/Users/richardquadling/Library/Preferences/PhpStorm2017.3/scratches/scratch_5.php
on line 14


There is a user note http://php.net/manual/en/function.array-udiff.php#86220

"It is not stated, by this function also diffs array1 to itself,
removing any duplicate values..."

This would seem to be the cause bit is clearly not the intent of the
function.

--
Richard Quadling
Christoph M. Becker
[PHP] Re: Should array_udiff be comparing elements from the same array?
November 10, 2017 06:30PM
On 10.11.2017 at 13:49, Richard Quadling wrote:

> Was testing array_udiff against some complex behaviour. Had an oddity.
> Reduced the code to a simple test ...
>
> 3v4l.org/XON0v
>
> <?php
>
> $array1 = array(1, 2, 3);
> $array2 = array(3, 4, 5);
>
> print_r(
> array_udiff(
> $array1,
> $array2,
> function ($a, $b) {
> static $tests = 0;
> echo 'array_udiff ', ++$tests, ' ', $a, ' vs ', $b, PHP_EOL;
>
> return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
> }
> )
> );
>
>
> The output is :
>
> array_udiff 1 1 vs 2 array_udiff 2 2 vs 3 array_udiff 3 3 vs 4 array_udiff
> 4 4 vs 5 array_udiff 5 1 vs 3 array_udiff 6 1 vs 2 array_udiff 7 2 vs 3
> array_udiff 8 2 vs 3 array_udiff 9 3 vs 3 Array ( [0] => 1 [1] => 2 )
>
>
> Tests 1 and 4 suggests that elements from with a single array are being
> compared. Is this expected behaviour?

It is not unexpected, if one considers the obvious implementation of the
function: sort the given arrays first[1], and then do the diff[2].
Sorting the arrays consequently uses the given comparison function, so
this can be applied on elements of the same array and on elements of
different arrays. Obviously, this requires all arrays to be of the same
shape, at least with regard to the comparison function. I think the man
page should clarify this.

[1]
<https://github.com/php/php-src/blob/ca1f07b6d733c2f422cb99ffb0e6122b2d5f8b5e/ext/standard/array.c#L5193>;
[2]
<https://github.com/php/php-src/blob/ca1f07b6d733c2f422cb99ffb0e6122b2d5f8b5e/ext/standard/array.c#L5235>;

--
Christoph M. Becker

--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php
On 10 November 2017 at 17:28, Christoph M. Becker <[email protected]> wrote:

> On 10.11.2017 at 13:49, Richard Quadling wrote:
>
> > Was testing array_udiff against some complex behaviour. Had an oddity.
> > Reduced the code to a simple test ...
> >
> > 3v4l.org/XON0v
> >
> > <?php
> >
> > $array1 = array(1, 2, 3);
> > $array2 = array(3, 4, 5);
> >
> > print_r(
> > array_udiff(
> > $array1,
> > $array2,
> > function ($a, $b) {
> > static $tests = 0;
> > echo 'array_udiff ', ++$tests, ' ', $a, ' vs ', $b, PHP_EOL;
> >
> > return ($a < $b) ? -1 : (($a > $b) ? 1 : 0);
> > }
> > )
> > );
> >
> >
> > The output is :
> >
> > array_udiff 1 1 vs 2 array_udiff 2 2 vs 3 array_udiff 3 3 vs 4
> array_udiff
> > 4 4 vs 5 array_udiff 5 1 vs 3 array_udiff 6 1 vs 2 array_udiff 7 2 vs 3
> > array_udiff 8 2 vs 3 array_udiff 9 3 vs 3 Array ( [0] => 1 [1] => 2 )
> >
> >
> > Tests 1 and 4 suggests that elements from with a single array are being
> > compared. Is this expected behaviour?
>
> It is not unexpected, if one considers the obvious implementation of the
> function: sort the given arrays first[1], and then do the diff[2].
> Sorting the arrays consequently uses the given comparison function, so
> this can be applied on elements of the same array and on elements of
> different arrays. Obviously, this requires all arrays to be of the same
> shape, at least with regard to the comparison function. I think the man
> page should clarify this.
>
> [1]
> <https://github.com/php/php-src/blob/ca1f07b6d733c2f422cb99ffb0e612
> 2b2d5f8b5e/ext/standard/array.c#L5193>
> [2]
> <https://github.com/php/php-src/blob/ca1f07b6d733c2f422cb99ffb0e612
> 2b2d5f8b5e/ext/standard/array.c#L5235>
>
> --
> Christoph M. Becker
>


It would be useful to have the knowledge in the callback that this is the
'sort' phase or the 'filter' phase.

This would also break if the object types were different and the callback
method has typehints for the parameters.

I guess this is one of those sets of methods that did the job perfectly
well, right up to the point someone decided to use it in an different way.

--
Richard Quadling
Sorry, only registered users may post in this forum.

Click here to login