当回调只返回0或1时,Array_uintersect()会给出意外的结果



我在array_uintersect()调用中有一个自定义回调,因为我需要区分大小写地比较两个元素中的字符串,同时比较两个多维数组之间的行。

function filterIdenticalEntriesCallback($a, $b) {
    echo "<tr><td>{$a['file']}</td><td>{$b['file']}</td><td>{$a['md5']}</td><td>{$b['md5']}</td></tr>";
    if ( (strcmp($a['file'], $b['file']) == 0 ) && ( strcmp($a['md5'],$b['md5']) == 0)){ 
        return 0;
    }
    return 1;
}
$vieja = array(
        array('file' => 'a', 'md5' => '1'),     //cambia
        array('file' => 'b', 'md5' => '2'),     //igual
        array('file' => 'c', 'md5' => '3'),     //igual
        array('file' => 'd', 'md5' => '4'),     //igual
);
$nueva = array(
        array('file' => 'a', 'md5' => '2'),     //cambia
        array('file' => 'b', 'md5' => '2'),     //igual
        array('file' => 'c', 'md5' => '3'),     //igual
        array('file' => 'd', 'md5' => '4'),     //igual
);
echo "<table>";
$ignorar = array_uintersect($nueva, $vieja, 'filterIdenticalEntriesCallback');
echo "</table>";
echo "<pre>";
print_r($ignorar);
echo "</pre>";
?>

输出
b   a   2   2
b   c   2   3
d   b   4   2
a   c   2   3
b   a   2   1
b   c   2   3
d   b   4   2
a   c   1   3
c   c   3   3
c   a   3   2
a   a   2   1
a   b   2   2
a   d   2   4
Array
(
    [2] => Array
        (
            [file] => c
            [md5] => 3
        )
)

我不明白为什么这段代码没有产生正确的输出,它应该是一个带有"B", "C"one_answers";D"元素,因为只有"元素与$vieja到$nueva不同…

如果我让两个"A"Elements =输出ok....

编辑:

function filterIdenticalEntriesCallback($a, $b) {
    echo "<tr><td>{$a['file']}</td><td>{$b['file']}</td><td>{$a['md5']}</td><td>{$b['md5']}</td></tr>";
    if (strcmp($a['file'], $b['file']) == 0 ){ 
        if ( strcmp($a['md5'],$b['md5']) == 0)
            return 0;
        else return 1;
    } else return -1;
}

使用这个回调是工作正常,但我仍然不明白为什么…什么-1和1回调结果意味着函数?我的意思是,我只需要相等的值…当回调返回0…我不需要其他情况

适合我的过滤器:

function filterIdenticalEntriesCallback($a, $b) {
        $cmp = strcmp($a['file'], $b['file']);
        if($cmp==0) {
                return strcmp($a['md5'], $b['md5']);
        } else {
                return $cmp;
        }
}

由于intersect的内部工作方式,如果第一个小于第二个,则必须返回一个负数;如果它们相同,则返回0;如果第一个大于第二个,则返回一个正数。这是nate以前观察到的。


一个更简洁的过滤函数:

function filterIdenticalEntriesCallback($a, $b) {
        if ($a==$b) {
                return 0;
        } else {
                return $a<$b ? -1 : 1;
        }
}

这是因为PHP的比较方式。从理论上讲,这个比较函数适用于任何两个相同类型的对象,只要你想确保所有的属性和它们的值都是相同的。

或者与一行相同:

function filterIdenticalEntriesCallback($a, $b) {
        return $a == $b ? 0 : ($a < $b ? -1 : 1);
}

PHP文档中的注释说,不能只返回0和1,还必须在适当的情况下返回-1。如果您也有返回-1的情况,您可能会有更好的运气。

是的,array_uintersect()需要由回调返回3-way比较,因为它的性能优化依赖于它。

因为要按照子数组元素在所有子数组中出现的顺序对子数组元素执行区分大小写的比较,并且因为所有子数组具有完全相同的键,所以可以使用"宇宙飞船"操作符进行无函数的三向求值。

代码(演示):

var_export(
    array_uintersect(
        $nueva,
        $vieja,
        fn($a, $b) => $a <=> $b
    )
);

如果行中元素的顺序不一致,可以使用:

fn($a, $b) => [$a['file'], $a['md5']] <=> [$b['file'], $b['md5']]
//             ^^rule 1^^  ^^rule 2^       ^^rule 1^^  ^^rule 2^

fn($a, $b) => $a['file'] <=> $b['file'] ?: $a['md5'] <=> $b['md5']
//            ^^^^rule 1 comparison^^^^    ^^tie breaking rule 2^^

,但我通常只在随后的tie-breakers中使用函数调用时才使用多个太空船操作符(作为性能优化)。

相关内容

  • 没有找到相关文章

最新更新