我想检查两个数组是否相等。我的意思是:相同的大小,相同的索引,相同的值。我该怎么做呢?

根据用户的建议使用!==,如果数组中至少有一个元素是不同的,我希望下面的代码会打印enter,但实际上并不是这样。

if (($_POST['atlOriginal'] !== $oldAtlPosition) 
    or ($_POST['atl'] !== $aext) 
    or ($_POST['sidesOriginal'] !== $oldSidePosition) 
    or ($_POST['sidesOriginal'] !== $sideext)) {

    echo "enter";
}

当前回答

如果你想生成一份详细的报告,你可以使用这样的东西:

function deepCompare(Array $a, Array $b, string $parentAKey, string $parentBKey, bool $compareInverted = true, bool $compareValues = true, string $log = '')
{
    foreach ($a as $aKey => $aValue) {
        $fullAKey = implode('.', [$parentAKey, $aKey]);
        $fullBKey = implode('.', [$parentBKey, $aKey]);
        if (! isset($b[$aKey])) {
            $log .= "⍰ {$fullAKey} has no equivalent {$fullBKey}\n";
        } else {
            $bValue = $b[$aKey];
            if (is_array($aValue)) {
                $log = deepCompare($aValue, $bValue, $fullAKey, $fullBKey, false, $compareValues, $log);
            } else {
              if ($compareValues) {
                  if ($aValue != $bValue) {
                      $log .= "≠ {$fullAKey} value differs from {$fullBKey}\n";
                  }
              }
            }
        }
    }
    if ($compareInverted) {
        $log = deepCompare($b, $a, $parentBKey, $parentAKey, false, false, $log);
    }
    return $log;
}

下面是一个例子:

$november = [
  'site1' => [
    'id' => 15,
    'name' => 'Brazil',
    'extendedHours' => 454,
  ],
  'site2' => [
    'id' => 43,
    'name' => 'Portugal',
    'extendedHours' => 448,
  ],
  'site3' => [
    'id' => 49,
    'name' => 'Spain',
    'extendedHours' => 0,
  ],  
  'totalExtendedHours' => 902,
];

$december = [
  'site1' => [
    'id' => 15,
    'name' => 'Brazil',
    'extendedHours' => 498,
  ],
  'site2' => [
    'id' => 43,
    'name' => 'Portugal',
    'extendedHours' => 409,
    'extraRequests' => 6,
  ],
  'totalExtendedHours' => 907,
  'totalExtraRequests' => 6,
];

echo deepCompare(
    $november,    -- origin array
    $december,    -- target array
    'Nov2022',    -- descriptive name of origin array
    'Dec2022',    -- descriptive name of target array
    true,         -- should also compare arrays in reverse order?
    true          -- should care about array values? (false = names only)
);

这个例子将输出:

≠ Nov2022.site1.extendedHours value differs from Dec2022.site1.extendedHours
≠ Nov2022.site2.extendedHours value differs from Dec2022.site2.extendedHours
⍰ Nov2022.site3 has no equivalent Dec2022.site3
≠ Nov2022.totalExtendedHours value differs from Dec2022.totalExtendedHours
⍰ Dec2022.site2.extraRequests has no equivalent Nov2022.site2.extraRequests
⍰ Dec2022.totalExtraRequests has no equivalent Nov2022.totalExtraRequests

我希望这能帮助到一些人。

其他回答

使用php函数array_diff(array1, array2);

它将返回数组之间的差值。如果是空的,那么它们相等。

例子:

$array1 = array(
    'a' => 'value1',

    'b' => 'value2',

    'c' => 'value3'
 );

$array2 = array(
    'a' => 'value1',

    'b' => 'value2',

    'c' => 'value4'
 );

$diff = array_diff(array1, array2);

var_dump($diff); 

//it will print array = (0 => ['c'] => 'value4' ) 

示例2:

$array1 = array(
    'a' => 'value1',

    'b' => 'value2',

    'c' => 'value3',
 );

$array2 = array(
    'a' => 'value1',

    'b' => 'value2',

    'c' => 'value3',
 );

$diff = array_diff(array1, array2);

var_dump($diff); 

//it will print empty; 

一种方法:(为https://www.rfc-editor.org/rfc/rfc6902#section-4.6实现“考虑平等”)

这种方式允许关联数组的成员顺序不同——例如,除了php,它们在每种语言中都被认为是相等的:)

// recursive ksort
function rksort($a) {
  if (!is_array($a)) {
    return $a;
  }
  foreach (array_keys($a) as $key) {
    $a[$key] = ksort($a[$key]);
  }
  // SORT_STRING seems required, as otherwise
  // numeric indices (e.g. "0") aren't sorted.
  ksort($a, SORT_STRING);
  return $a;
}


// Per https://www.rfc-editor.org/rfc/rfc6902#section-4.6
function considered_equal($a1, $a2) {
  return json_encode(rksort($a1)) === json_encode(rksort($a2));
}
if (array_diff($a,$b) == array_diff($b,$a)) {
  // Equals
}

if (array_diff($a,$b) != array_diff($b,$a)) {
  // Not Equals
}

从我的观点来看,最好使用array_diff而不是array_intersect,因为这种性质的检查通常返回的差异小于相似点,这样bool转换占用的内存更少。

注意,此解决方案适用于普通数组,并补充了上面发布的仅对字典有效的==和===。

比较两个数组是否相等的正确方法是使用严格相等(===),这是递归比较。现有的答案无法递归地对任意数组(具有任意深度和顺序的数组,包含顺序数组和关联数组的混合)进行排序,因此无法处理任意数组的比较。顺序数组是具有顺序键(0,1,2,3…)的关联数组,而关联数组没有顺序键。

要对这些任意数组排序,我们必须:

向下遍历没有更多子数组的叶节点 通过序列化顺序数组,然后排序它们(以消除必须使用自定义比较器的需要) 按键对关联数组排序

下面的代码实现了上述解决方案。欢迎对代码进行改进。

function recur_sort( &$array ) {
    foreach ( $array as &$value ) {
       if ( is_array( $value ) ) recur_sort( $value );
    }

    if ( is_sequential_array( $array ) ) {
        $array = array_map( function( $el ) { return json_encode( $el ); }, $array  );
        sort( $array, SORT_STRING );
        $array = array_map( function( $el ) { return json_decode( $el, true ); }, $array  );
        return;
    } else {
        return ksort( $array );
    }
}

function is_sequential_array(Array &$a) {
    $n = count($a);
    for($i=0; $i<$n; $i++) {
        if(!array_key_exists($i, $a)) {
            return false;
        }
    }
    return true;
}

示例(在PHPUnit中):

//A stricter and recursive assertEqualsCanonicalizing
public function assertSameCanonicalizing( $expected, $actual ) {
    recur_sort( $expected );
    recur_sort( $actual );
    $this->assertSame( $expected, $actual );
}

下面的解决方案使用可作为回调传递的自定义相等函数。注意,它不检查数组的顺序。

trait AssertTrait
{
    /**
     * Determine if two arrays have the same elements, possibly in different orders. Elements comparison function must be passed as argument.
     *
     * @param array<mixed> $expected
     * @param array<mixed> $actual
     *
     * @throws InvalidArgumentException
     */
    public static function assertArraysContainSameElements(array $expected, array $actual, callable $comparisonFunction): void
    {
        Assert::assertEquals(\count($expected), \count($actual));

        self::assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes($expected, $actual, $comparisonFunction);
        self::assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes($actual, $expected, $comparisonFunction);
    }

    /**
     * @param array<mixed> $needles
     * @param array<mixed> $haystack
     *
     * @throws InvalidArgumentException
     */
    private static function assertEveryElementOfArrayIsInAnotherArrayTheSameAmountOfTimes(
        array $needles,
        array $haystack,
        callable $comparisonFunction
    ): void {
        Assert::assertLessThanOrEqual(\count($needles), \count($haystack));

        foreach ($needles as $expectedElement) {
            $matchesOfExpectedElementInExpected = \array_filter(
                $needles,
                static fn($element): bool => $comparisonFunction($expectedElement, $element),
            );

            $matchesOfExpectedElementInActual = \array_filter(
                $haystack,
                static fn($element): bool => $comparisonFunction($expectedElement, $element),
            );

            Assert::assertEquals(\count($matchesOfExpectedElementInExpected), \count($matchesOfExpectedElementInActual));
        }
    }
}

我通常在数据库集成测试中使用它,当我想确保返回预期的元素,但我不关心排序。