array_udiff似乎无法正常工作

3

我尝试使用array_udiff比较两个数组,但结果很奇怪。看起来array_udiff没有得到正确的答案。这里是实时演示。结果应该是一个空数组,但留下了一个未被过滤的元素。

<?php

$string = '{
  "sakiniai": [

      {
        "Faktas": "A",
        "value": "true"
      },
      {
        "Faktas": "B",
        "value": "true"
      },
      {
        "Faktas": "A",
        "value": "false"
      }
  ]
}';

$sakiniais = json_decode($string, true)['sakiniai'];


$v = $sakiniais[0];
$arr[] = $v;
$v['value'] = $v['value'] == "true" ? "false" : "true";
$arr[] = $v;
var_dump($arr);
var_dump($sakiniais);


print_r(array_udiff($arr, $sakiniais, function($a, $b){
/*
var_dump($a);
var_dump($b);
var_dump($a == $b);
echo "\n\n\n";
*/
return $a == $b ? 0 : -1;}
));

输出

    array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}
array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}
Array
(
    [1] => Array
        (
            [Faktas] => A
            [value] => false
        )

)

也许你应该描述一下你想要实现什么。我找不到原来提出这个要求的问题。 - RiggsFolly
@RiggsFolly 在这里我比较了两个数组,第一个数组的所有元素都在第二个数组中,所以预期输出应该是一个空数组。但结果数组却有一个元素。 - LF00
2个回答

10
问题在于array_udiff没有对所有值进行比较,这似乎是由于您的比较函数引起的。
array_udiff()期望可调用的函数是真正的比较函数,但您始终返回0和-1,但从不返回1。
在执行其任务之前,array_udiff()尝试对两个数组进行排序并删除重复项。如果它不能依赖于您的比较函数,则无法执行所有所需的比较,并且某些值会被“跳过”。
请查看文档中的所有注释,特别是napcoder评论

请注意,比较函数也在内部使用,以对数组进行排序,并选择下一轮要比较的元素。

如果您的比较函数不真正进行比较(即如果元素相等则返回0,否则返回1),则将收到意外结果。

这可以通过查看您的数组来证明

$arr

array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

和 $sakiniais

array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

你应该期望测试两个数组之间的所有组合,但是被测试的组合(如下所示)不包括 A-False vs. A-False。
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
bool(true)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
}
array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
bool(false)



array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
}
array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
}
bool(false)

这篇文章的正确答案中,有关于array_udiff如何工作的其他有用见解。
你可以像这样更改你的返回语句。
if ($a < $b) {
    return -1;
} elseif ($a > $b) {
    return 1;
} else {
    return 0;
}

(如果你想知道如何比较两个数组大小,可以查看this link,在“与各种类型的比较”部分和“示例#2 标准数组比较转录”示例中了解更多信息)

是的,我也发现array_udiff没有比较所有值。 - LF00
我更新了答案。你必须实现一个真正的比较函数(可以按可靠的顺序对数组元素进行排序)。 - LombaX
添加了一个示例,说明如何重构比较函数。 - LombaX

0

没什么奇怪的,一切都按预期工作。看看比较数组:

$arraysAreEqual = ($a == $b); // TRUE if $a and $b have the same key/value pairs.
$arraysAreEqual = ($a === $b); // TRUE if $a and $b have the same key/value pairs in the same order and of the same types.

所以,$arr [0] == $sakiniai [0] 是真的,但 $arr [1] == $sakiniai [2] 是假的,输出是 $arr [1]。 $arr
array(2) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

$sakiniai

array(3) {
  [0]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(4) "true"
  }
  [1]=>
  array(2) {
    ["Faktas"]=>
    string(1) "B"
    ["value"]=>
    string(4) "true"
  }
  [2]=>
  array(2) {
    ["Faktas"]=>
    string(1) "A"
    ["value"]=>
    string(5) "false"
  }
}

结果

Array
(
    [1] => Array
        (
            [Faktas] => A
            [value] => false
        )

)

$arr[1] == $sakiniai[2] 是错误的吗?为什么? - LF00
因为键不相同 1 != 2 - rokas
键不是1、2,而是Faktas和值。 - LF00
不,你错了。array_udiff 用于计算单维数组之间的差异,因此如果您将多维数组作为参数传递,该函数将从第一维中获取键。如果您想比较多维数组,则应编写自己的函数。 - rokas
你看过我在array_udiff中的compare函数吗?这里是手册 - LF00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接