PHP中按顺序比较数组的最有效方法是什么?

4

在PHP中有这两个数组:

$array1 = [
    2 => 'Search',
    1 => 'Front-End / GUI'
];
$array2 = [
    1 => 'Front-End / GUI',
    2 => 'Search'
];

大多数数组比较函数对顺序不关心。使用array_diff会得到一个空数组。
关于顺序,比较两个数组最有效/最短/最简洁的方法是什么?
  1. 显示它们是否相等(true / false)?
  2. 显示区别(例如PHPUnit)?
在PHPUnit中运行 $this->assertEquals($array1,$array2); 理想情况下应该产生类似以下结果:
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
-    2 => 'Search'
-    1 => 'Front-End / GUI'
+    1 => 'Front-End / GUI'
+    2 => 'Search'
 )

更新 - 解决方案

只有在所有元素相同但顺序不同的情况下,这将生成一种类似的差异。PHPUnit测试:

public function test...() {
    $actual = someCall();
    $expected = [...];

    // tests for same elements
    $this->assertEquals( $expected, $actual );

    // tests for same order
    $diff = $this->array_diff_order( $expected, $actual );
    $this->assertTrue( $expected === $actual, "Failed asserting that two arrays are equal order.\n--- Expected\n+++ Actual\n@@ @@\n Array(\n$diff )" );
}

private function array_diff_order( $array1, $array2 ) {
    $out = '';
    while ((list($key1, $val1) = each($array1)) && (list($key2, $val2) = each($array2)) ) {
        if($key1 != $key2 || $val1 != $val2) $out .= "-    $key1 => '$val1' \n+    $key2 => '$val2'\n";
    }
    return $out;
}
3个回答

8

您可以使用 === 运算符

$array = array(1 => "test", 2=> "testing");
$array2 = array(1 => "test", 2=> "testing");

var_dump($array === $array2);

$array2 = array(2 => "test", 1=> "testing");
var_dump($array === $array2);

返回

boolean true
boolean false

然后使用array_diff_assoc()函数查找差异。
while ((list($key1, $val1) = each($array)) && (list($key2, $val2) = each($array2)) ) {
    if($key1 != $key2 || $val1 != $val2) echo "- $key1 - $val1 \n + $key2 - $val2";
}

应该输出一些订单内容

使用您的数组,这给出了以下结果:

  • 2-搜索+1-前端/GUI
  • 1-前端/GUI+2-搜索

您可以根据需要更改输出结果


那回答了问题1。有人想问问题2吗? - Joe Z
那么使用array_diff_assoc()函数来查找差异,这难道不回答问题2了吗? - exussum
正如我所提到的,array_diff_assoc() 不会检查顺序。Marc 的第二个数组与我的不同。 - Joe Z
它们是相同的,你可以通过var_dump确认,为什么顺序很重要? - exussum
在这种情况下,顺序确实很重要 :) 这就是为什么这个问题与SE上的其他成千上万个问题不同的原因。 - Joe Z
更新了一个简单的while循环。 - exussum

0
如果您正在寻找一种生成类似差异的输出的解决方案,我认为这是迭代器发挥作用的地方:
只需为每个数组拥有两个迭代器,在一个循环中同时遍历它们并比较键值对,就可以完成几乎所有需要的操作:
$array1 = [
    2 => 'Search',
    1 => 'Front-End / GUI'
];
$array2 = [
    1 => 'Front-End / GUI',
    2 => 'Search'
];

$it0 = new ArrayIterator($array1);
$it1 = new ArrayIterator($array2);

while ($it0->valid() || $it1->valid()) {
    if ($it0->valid() && $it1->valid()) {
        if ($it0->key() != $it1->key() || $it0->current() != $it1->current()) {
            print "- ".$it0->key().' => '.$it0->current()."\n";
            print "+ ".$it1->key().' => '.$it1->current()."\n";
        }
        $it0->next();
        $it1->next();
    } elseif ($it0->valid()) {
        print "- ".$it0->key().' => '.$it0->current()."\n";
        $it0->next();
    } elseif ($it1->valid()) {
        print "+ ".$it1->key().' => '.$it1->current()."\n";
        $it1->next();
    }
}

将输出类似于:

- 2 => Search
+ 1 => Front-End / GUI
- 1 => Front-End / GUI
+ 2 => Search

当然,这个想法应该扩展到使用RecursiveArrayIterator处理嵌套数组,并且可能还要更好地格式化输出。


这确实可以回答问题2。最好找一些更简单、更清洁、更符合断言的内容。 - Joe Z
如果可能的话,我也可以使用foreach,但我正在寻找一些简洁的东西。 - Joe Z
我认为foreach只有在两个数组具有相同长度时才能工作,否则您将不得不在循环之外以某种方式处理非重叠部分。我认为您也可以始终隐藏函数背后的逻辑,创建差异很困难(-: - complex857

-3

你需要使用array_diff_assoc(),它可以比较值和键。而array_diff()只会考虑值。


跟进:这里运行正常:

php > $arr1 = array(2 => 'Search', 1 => 'Front');
php > $arr2 = array(1 => 'Search', 2 => 'Front');
php > var_dump(array_diff_assoc($arr1, $arr2));
array(2) {
  [2]=>
  string(6) "Search"
  [1]=>
  string(5) "Front"
}

array_diff_assoc() 也会返回一个空数组。 - Joe Z
你的第二个数组和我的不同。 - Joe Z
@joe: PHP在考虑数组内部排序时并不认为它有所不同。这完全取决于解释器内部内存指针的状态,而这些指针不会暴露在脚本级别上。如果键和/或值是相同的,则对于array_diff/array_diff_assoc目的而言是相同的。 - Marc B

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