4

测试脚本

$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例如)。

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

4

5 回答 5

5

array_uintersect文档中没有提到的是,在内部,PHP首先对所有数组进行排序,从左到右。只有数组排序之后,PHP 才会遍历它们(同样,从左到右)以找到交集。

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

zend_sort实现通常使用二等分快速排序实现。对于您示例中大小的数组,PHP 使用插入排序。对于大型数组,PHP 使用 3 或 5 点枢轴来提高最坏情况的复杂性

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

于 2016-10-28T20:57:56.563 回答
4

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

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

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

print_r($a);

输出

Array
(
    [1] => bar
)

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

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

于 2016-10-27T15:54:37.917 回答
2

我相信前两个调用被用于在内部算法中播种变量。但是由于您没有返回算法可以用来确定相等/排序的任何内容,因此它只运行接下来的两个。

如果您实际返回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
)
于 2016-10-27T16:00:37.860 回答
0

我想你正在寻找这个;)

$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"
  }
}

更新:它使用该方法返回您想要的结果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)
  }
}
于 2016-10-27T16:11:49.207 回答
-4
<?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)
于 2016-10-27T16:07:17.370 回答