【问题标题】:array_uintersect() gives unexpected results when callback only returns 0 or 1当回调仅返回 0 或 1 时,array_uintersect() 会给出意外结果
【发布时间】:2023-03-18 11:31:01
【问题描述】:

我在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”和“D”元素的数组,因为只有“A”元素从 $vieja 到 $新...

如果我让两个“A”元素都等于输出就可以了......

编辑:

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...我不需要其他情况...

【问题讨论】:

  • 您的比较函数只返回三个可能返回值中的两个。这可能会导致您的问题。
  • 该函数的文档解释了回调返回值:php.net/array_uintersect

标签: php arrays multidimensional-array callback array-intersect


【解决方案1】:

适合我的过滤器:

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

由于 intersect 内部的工作方式,如果第一个小于第二个,则必须返回负数,如果相同则返回 0,如果第一个大于第二个,则返回正数。 This has been observed before by 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);
}

【讨论】:

  • 但是,$a 和 $b 是两个数组...可以这样比较两个数组吗?让我们看看我是否理解正确:PHP 正在以二进制模式比较数组中的数据?显然忽略了数组键..
  • 看起来你是对的......单线回调就像一个魅力;)所以......提出了一个新问题......这不是和array_intersect一样吗? :P 编辑:我会回答自己...不一样,因为它不起作用哈哈! :) 谢谢李维斯!
  • @KnF 是的,不一样,因为array_intersect 比较值,而== 将比较属性和它们的值,在数组的情况下它是它们的键和值。跨度>
  • 但是为什么比较会以这种方式工作(需要返回 -1、0 或 1 而不是布尔值)?
  • @KevinC。在内部,它必须执行排序操作。这只是内部工作的一部分。
【解决方案2】:

PHP documentation 中的一条评论说你不能只返回 0 和 1,但你还必须有在适当的时候返回 -1 的情况。如果你也有一个返回 -1 的案例,你可能会有更好的运气。

【讨论】:

    【解决方案3】:

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

    因为您要按照子数组元素在所有子数组中出现的顺序对子数组元素执行区分大小写的比较,并且因为所有子数组都具有完全相同的键,所以您可以使用“宇宙飞船运算符”进行无功能的 3 向评估”。

    代码:(Demo)

    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^^
    

    但如果我在随后的决胜局中使用函数调用(作为性能优化),我通常只使用多个宇宙飞船运算符。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-14
      相关资源
      最近更新 更多