为什么 array_uintersect() 比较 array1 和 array2、array1 和 array1 以及 array2 和 array2 之间的元素?

Why does array_uintersect() compare elements between array1 & array2, array1 & array1, and array2 & array2?

测试脚本

$i = 0;
array_uintersect(['foo', 'bar'], ['baz', 'qux'], function($a, $b) use (&$i) {
    print_r([$a, $b, $i++]);
});

实际结果

Array
(
    [0] => bar
    [1] => foo
    [2] => 0
)
Array
(
    [0] => qux
    [1] => baz
    [2] => 1
)
Array
(
    [0] => bar
    [1] => qux
    [2] => 2
)
Array
(
    [0] => bar
    [1] => foo
    [2] => 3
)

预期结果

Array
(
    [0] => foo
    [1] => baz
    [2] => 0
)
Array
(
    [0] => bar
    [1] => qux
    [2] => 1
)

换句话说,我期望传递给回调的是左数组的当前元素和右数组的当前元素。

此外,如果我要将另一个数组传递给 array_uintersect,我希望应用相同的逻辑 - 将另一个参数传递给回调(例如 $c)。

有人可以解释这种行为吗?

我不知道为什么除了比较数组的值之外,您对比较回调有任何期望。回调的唯一目的是比较两个数组中的下一对项目。

函数returns两个数组相交的结果。在回调中,您表达了应该如何比较这些值的想法。例如,下面的代码假设应该通过比较字符串的第一个字符来执行交集:

$a = array_uintersect(['foo', 'bar'], ['baz', 'qux'], function($a, $b) {
  return strcmp($a[0], $b[0]);
});

print_r($a);

输出

Array
(
    [1] => bar
)

传递给回调的项目顺序由 PHP 内部指定,将来可能很容易更改。

所以比较函数不应该做任何事情,除了比较两个变量。在官方文档中甚至没有暗示将回调用于任何其他目的。

我相信前两个调用被用来为内部算法中的变量播种。但是由于您没有 return 任何算法可以用来确定 equality/sorting 的东西,它只运行接下来的两个。

如果您实际上 return 01-1 那么您会看到计算交集所需的完整比较链:

$i = 0;
array_uintersect(['foo', 'bar'], ['baz', 'qux'], function($a, $b) use (&$i) {
    print_r([$a, $b, $i++]);

    if ($a === $b) return 0;
    if ($a  >  $b) return 1;
    return -1;
});

产量:

Array
(
    [0] => bar
    [1] => foo
    [2] => 0
)
Array
(
    [0] => qux
    [1] => baz
    [2] => 1
)
Array
(
    [0] => bar
    [1] => baz
    [2] => 2
)
Array
(
    [0] => foo
    [1] => baz
    [2] => 3
)
Array
(
    [0] => foo
    [1] => baz
    [2] => 4
)
Array
(
    [0] => foo
    [1] => qux
    [2] => 5
)
<?php
    $i  = 0;
    $r1 = ['foo', 'bar'];
    $r2 = ['baz', 'qux'];
    $result = array_uintersect($r1, $r2, function($a, $b){
        return ($a[0]> $b[0]);
    });


    var_dump($result);
    // YIELDS::
    array (size=2)
      0 => string 'foo' (length=3)
      1 => string 'bar' (length=3)

我想你正在找这个 ;)

$result = array_map(function($a, $b) {
    return [$a, $b];
}, ['foo', 'bar'], ['baz', 'qux']);
var_dump($result);

这将输出

array(2) {
  [0]=>
  array(2) {
    [0]=>
    string(3) "foo"
    [1]=>
    string(3) "baz"
  }
  [1]=>
  array(2) {
    [0]=>
    string(3) "bar"
    [1]=>
    string(3) "qux"
  }
}

更新:它 returns 使用 array_uintersect 方法得到您想要的结果。这不是最有效的方法,也没有用不同的数据集等进行测试,但应该可以。

$entities = [
    [
        'id' => 1,
        'timestamp' => 1234
    ],
    [
        'id' => 2,
        'timestamp' => 12345
    ],
    [
        'id' => 3,
        'timestamp' => 123456
    ],
    [
        'id' => 8,
        'timestamp' => 123456
    ],
    [
        'id' => 10,
        'timestamp' => 123456
    ],
    [
        'id' => 11,
        'timestamp' => 123456
    ],
    [
        'id' => 12,
        'timestamp' => 123456
    ]
];

$identities = [1, 11, 2, 8, 10];

$result = array_uintersect($entities, $identities, function($a, $b) {

    // Both array skip
    if (is_array($a) && is_array($b)) {
        if ($a['id'] > $b['id']) {
            return 1;
        }
        return -1;
    }

    // Both int skip
    if (is_int($a) && is_int($b)) {
        if ($a > $b) {
            return 1;
        }
        return -1;
    }

    // $a is array
    if (is_array($a)) {
        if ($a['id'] == $b) {
            return 0;
        }
        elseif ($a['id'] > $b) {
            return 1;
        }
        return -1;
    }

    // $b is array
    if($b['id'] == $a) {
        return 0;
    }
    if($a > $b['id']) {
        return 1;
    }

    return -1;
});
var_dump($result);

结果

array(5) {
  [0]=>
  array(2) {
    ["id"]=>
    int(1)
    ["timestamp"]=>
    int(1234)
  }
  [1]=>
  array(2) {
    ["id"]=>
    int(2)
    ["timestamp"]=>
    int(12345)
  }
  [3]=>
  array(2) {
    ["id"]=>
    int(8)
    ["timestamp"]=>
    int(123456)
  }
  [4]=>
  array(2) {
    ["id"]=>
    int(10)
    ["timestamp"]=>
    int(123456)
  }
  [5]=>
  array(2) {
    ["id"]=>
    int(11)
    ["timestamp"]=>
    int(123456)
  }
}

array_uintersect docs is that, internally, PHP sorts all the arrays中没有提到的先从左到右。只有 数组排序后 PHP 遍历它们(再次从左到右)以找到交集。

第三个参数(比较函数)被传递给内部排序算法,而不是相交算法。因此,看到的调试输出是确定排序的排序算法。

zend_sort implementation generally uses a bisecting quick sort implementation. For arrays of the size in your example, PHP uses insertion sort. For large arrays, PHP uses a 3 or 5 point pivot so as to improve worst-case complexity.

由于您没有显式地从比较函数返回任何值,PHP 默认返回 null (0),并且由于 PHP 使用插入排序,您看到 O( n*n) 排序遍历所有组合时的行为。