PHP - проверить, равны ли два массива
Я хотел бы проверить, равны ли два массива. Я имею в виду: тот же размер, тот же индекс, те же значения. Как я могу это сделать?
С помощью ===
как предполагается пользователем, я ожидаю, что следующее напечатало бы ввод, если хотя бы один элемент в массиве (ах) отличается, но на самом деле это не так.
if (($_POST['atlOriginal'] !=== $oldAtlPosition)
or ($_POST['atl'] !=== $aext)
or ($_POST['sidesOriginal'] !=== $oldSidePosition)
or ($_POST['sidesOriginal'] !=== $sideext)) {
echo "enter";
}
23 ответа
$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.
Смотрите Операторы массива.
РЕДАКТИРОВАТЬ
Оператор неравенства !=
в то время как неидентичный оператор !==
соответствовать оператору равенства ==
и оператор идентичности ===
,
По этой странице.
ПРИМЕЧАНИЕ. Принятый ответ работает для ассоциативных массивов, но не работает должным образом с индексированными массивами (поясняется ниже). Если вы хотите сравнить любой из них, используйте это решение. Кроме того, эта функция может не работать с многомерными массивами (из-за природы функции array_diff).
Тестирование двух индексированных массивов, элементы которых расположены в разном порядке, используя $a == $b
или же $a === $b
не удается, например:
<?php
(array("x","y") == array("y","x")) === false;
?>
Это потому что выше означает:
array(0 => "x", 1 => "y")
против array(0 => "y", 1 => "x")
,
Чтобы решить эту проблему, используйте:
<?php
function array_equal($a, $b) {
return (
is_array($a)
&& is_array($b)
&& count($a) == count($b)
&& array_diff($a, $b) === array_diff($b, $a)
);
}
?>
Добавлено сравнение размеров массивов (предложено super_ton), так как это может улучшить скорость.
Попробуй сериализовать. Это также проверит вложенные подмассивы.
$foo =serialize($array_foo);
$bar =serialize($array_bar);
if ($foo == $bar) echo "Foo and bar are equal";
Рабочее краткое решение, которое работает даже с массивами, ключи которых даны в разном порядке:
public static function arrays_are_equal($array1, $array2)
{
array_multisort($array1);
array_multisort($array2);
return ( serialize($array1) === serialize($array2) );
}
function compareIsEqualArray(array $array1,array $array):bool
{
return (array_diff($array1,$array2)==[] && array_diff($array2,$array1)==[]);
}
Сравните их как другие значения:
if($array_a == $array_b) {
//they are the same
}
Вы можете прочитать обо всех операторах массива здесь: http://php.net/manual/en/language.operators.array.php Например, обратите внимание, что ===
также проверяет, что типы и порядок элементов в массивах одинаковы.
if (array_diff($a,$b) == array_diff($b,$a)) {
// Equals
}
if (array_diff($a,$b) != array_diff($b,$a)) {
// Not Equals
}
Из моего pov лучше использовать array_diff, чем array_intersect, потому что с проверками такого рода возвращаемые различия обычно меньше, чем сходства, таким образом, преобразование bool требует меньше памяти.
Редактировать Обратите внимание, что это решение предназначено для простых массивов и дополняет опубликованное выше == и ===, которое действительно только для словарей.
!===
не будет работать, потому что это синтаксическая ошибка. Правильный путь !==
(не три символа "равно")
Ты можешь использовать array_diff_assoc
чтобы проверить различия между ними.
Другой метод проверки равенства независимо от порядка значений работает с использованием http://php.net/manual/en/function.array-intersect.php, например так:
$array1 = array(2,5,3);
$array2 = array(5,2,3);
if($array1 === array_intersect($array1, $array2) && $array2 === array_intersect($array2, $array1)) {
echo 'Equal';
} else {
echo 'Not equal';
}
Вот версия, которая работает также с многомерными массивами, используя http://php.net/manual/en/function.array-uintersect.php:
$array1 = array(
array(5, 2),
array(3, 6),
array(2, 9, 4)
);
$array2 = array(
array(3, 6),
array(2, 9, 4),
array(5, 2)
);
if($array1 === array_uintersect($array1, $array2, 'compare') && $array2 === array_uintersect($array2, $array1, 'compare')) {
echo 'Equal';
} else {
echo 'Not equal';
}
function compare($v1, $v2) {
if ($v1===$v2) {
return 0;
}
if ($v1 > $v2) return 1;
return -1;
}
array_diff - вычисляет разницу массивов
http://php.net/manual/en/function.array-diff.php
array array_diff ( array $array1 , array $array2 [, array $... ] )
Сравнивает
array1
против одного или нескольких других массивов и возвращает значения вarray1
которые отсутствуют ни в одном из других массивов.
Синтаксическая проблема в ваших массивах
$array1 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$array2 = array(
'a' => 'value1',
'b' => 'value2',
'c' => 'value3',
);
$diff = array_diff($array1, $array2);
var_dump($diff);
Один из способов: (реализация "считается равным" для http://tools.ietf.org/html/rfc6902)
Этот способ позволяет ассоциативные массивы, члены которых упорядочены по-разному - например, они будут считаться равными на всех языках, кроме 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 http://tools.ietf.org/html/rfc6902#section-4.6
function considered_equal($a1, $a2) {
return json_encode(rksort($a1)) === json_encode(rksort($a2));
}
Вот пример того, как сравнивать массивы и узнавать, чем они отличаются.
$array1 = ['1' => 'XXX', 'second' => [
'a' => ['test' => '2'],
'b' => 'test'
], 'b' => ['no test']];
$array2 = [
'1' => 'XX',
'second' => [
'a' => ['test' => '5', 'z' => 5],
'b' => 'test'
],
'test'
];
function compareArrayValues($arrayOne, $arrayTwo, &$diff = [], $reversed = false)
{
foreach ($arrayOne as $key => $val) {
if (!isset($arrayTwo[$key])) {
$diff[$key] = 'MISSING IN ' . ($reversed ? 'FIRST' : 'SECOND');
} else if (is_array($val) && (json_encode($arrayOne[$key]) !== json_encode($arrayTwo[$key]))) {
compareArrayValues($arrayOne[$key], $arrayTwo[$key], $diff[$key], $reversed);
} else if ($arrayOne[$key] !== $arrayTwo[$key]) {
$diff[$key] = 'DIFFERENT';
}
}
}
$diff = [];
$diffSecond = [];
compareArrayValues($array1, $array2, $diff);
compareArrayValues($array2, $array1, $diffSecond, true);
print_r($diff);
print_r($diffSecond);
print_r(array_merge($diff, $diffSecond));
Результат:
Array
(
[0] => DIFFERENT
[second] => Array
(
[a] => Array
(
[test] => DIFFERENT
[z] => MISSING IN FIRST
)
)
[b] => MISSING IN SECOND
[1] => DIFFERENT
[2] => MISSING IN FIRST
)
Данный:
$array1 = ['a', 'b', '3'];
$array2 = ['a', 'b', '3'];
$array1 == $array2 //true
$array1 === $array2 //true
Данный:
$array1 = ['a', 'b', 3];
$array2 = ['a', 'b', '3'];
$array1 == $array2 //true
$array1 === $array2 //false
Данный:
$array1 = ['3', 'a', 'b'];
$array2 = ['a', 'b', '3'];
$array1 == $array2 //false
$array1 === $array2 //false
Решение, отсортировать в том же порядке
$array1 = ['3', 'a', 'b'];
$array2 = ['a', 'b', '3'];
sort($array1);
sort($array2);
$array1 == $array2 //true
$array1 === $array2 //true
Используйте функцию 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;
Если вы хотите проверить неассоциативные массивы, вот решение:
$a = ['blog', 'company'];
$b = ['company', 'blog'];
(count(array_unique(array_merge($a, $b))) === count($a)) ? 'Equals' : 'Not Equals';
// Equals
Если вы хотите проверить, что ваши массивы имеют строго равные (
===
) ассоциации ключей и значений можно использовать следующую функцию:
function array_eq($a, $b) {
// If the objects are not arrays or differ in their size, they cannot be equal
if (!is_array($a) || !is_array($b) || count($a) !== count($b)) {
return false;
}
// If the arrays of keys are not strictly equal (after sorting),
// the original arrays are not strictly equal either
$a_keys = array_keys($a);
$b_keys = array_keys($b);
array_multisort($a_keys);
array_multisort($b_keys);
if ($a_keys !== $b_keys) {
return false;
}
// Comparing values
foreach ($a_keys as $key) {
$a_value = $a[$key];
$b_value = $b[$key];
// Either the objects are strictly equal or they are arrays
// which are equal according to our definition. Otherwise they
// are different.
if ($a_value !== $b_value && !array_eq($a_value, $b_value)) {
return false;
}
}
return true;
}
Для сравнения значений ваших массивов, также многомерных, ассоциативных и в любой комбинации:
/**
* @see PHPUnit Assert::assertEqualsCanonicalizing()
* @return true if all keys and values are equal and of the same type,
* irregardless of items or keys order
*/
function array_vals_equal(array $a, array $b): bool {
// sort multi-dimensional recursive
$_deep_sort = function (array $a) use (&$_deep_sort): array{
// sort discarding index association or sort keys, depending on array type
array_is_list($a) ? sort($a) : ksort($a);
return array_map(fn($v) => is_array($v) ? $_deep_sort($v) : $v, $a);
};
// operator === checks that the count, types and order of the elements are the same
return $_deep_sort($a) === $_deep_sort($b);
}
// Test cases
assertEquals(array_vals_equal([1], [1]), true, 'simple eq');
assertEquals(array_vals_equal([0], [false]), false, 'simple eq');
assertEquals(array_vals_equal([0], [null]), false, 'simple eq');
assertEquals(array_vals_equal([0, 1], [1, 0]), true, 'simple eq, diff order');
assertEquals(array_vals_equal([0, 1, 2], [1, 0]), false, 'diff count');
assertEquals(array_vals_equal([0, 1], [0, 1, 2]), false, 'diff count 2');
assertEquals(array_vals_equal([1, 2], [1, 2, 'hello']), false, 'diff count 3');
//
assertEquals(array_vals_equal([1, 2, 2], [2, 1, 1]), false, 'same vals repeated');
assertEquals(array_vals_equal([1, 2, 2], [2, 2, 1]), true, 'same vals, different order');
//
assertEquals(array_vals_equal([1, 2, 3], ['1', '2', '3']), false, 'int should not be eq string');
assertEquals(array_vals_equal([0 => 'a', 1 => 'b'], [0 => 'b', 1 => 'a']), true, 'same vals, diff order');
assertEquals(array_vals_equal(['a', 'b'], [3 => 'b', 5 => 'a']), true, 'same vals, diff indexes');
// associative arrays whose members are ordered differently
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['bb' => 'b', 'aa' => 'a']), true, 'dict with different order');
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['aa' => 'a']), false, 'a key is missing');
assertEquals(array_vals_equal(['aa' => 'a', 'bb' => 'b'], ['aa' => 'a', 'zz' => 'b']), false, 'dict same vals diff key');
// nested arrays with keys in different order
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => ['bb' => 'b', 'aa' => 'a']],
['aa' => 'a', 'bb' => ['aa' => 'a', 'bb' => 'b']]
), true, 'dict multi 2 level, keys in different order');
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => ['aa2' => 'a', 'bb2' => ['aa3' => 'a', 'bb3' => 'b']]],
['aa' => 'a', 'bb' => ['aa2' => 'a', 'bb2' => ['aa3' => 'a', 'bb3' => 'b']]]
), true, 'dict multi 3 level');
assertEquals(array_vals_equal(
['aa' => 'a', 'bb' => [0, 1]],
['aa' => 'a', 'bb' => [1, 0]]
), true, 'dict multi level, 2^ level sequential in different order');
assertEquals(array_vals_equal([[0, 1], ['a', 'b']], [['b', 'a'], [1, 0]]), true, 'multi level sequential');
Если вы хотите создать подробный отчет, вы можете использовать что-то вроде этого:
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
Я надеюсь, что это поможет кому-то.
Следующее решение работает с настраиваемыми функциями равенства , которые можно передать в качестве обратного вызова. Обратите внимание, что он не проверяет порядок массивов.
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));
}
}
}
Я обычно использую его в тестах интеграции базы данных, когда хочу убедиться, что ожидаемые элементы возвращаются, но меня не волнует сортировка.
Правильный способ сравнить, равны ли два массива, - использовать строгое равенство (===), которое сравнивается рекурсивно. Существующие ответы не могут рекурсивно отсортировать произвольный массив (массив произвольной глубины и порядка, содержащий смесь последовательных и ассоциативных массивов) и, следовательно, не могут обрабатывать сравнения произвольных массивов. Последовательные массивы - это ассоциативные массивы с последовательным ключом (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 );
}