比较php中的数组,不关心顺序

问题描述 投票:13回答:5

我有两个数组$ a和$ b,需要检查它们是否包含完全相同的元素(与顺序无关)。我正在考虑使用

if (sizeof($a)==sizeof($b) AND array_diff($a,$b)==array())
{

}

但是我不熟悉PHP,所以我想知道:还有更好的方法吗?

由于我需要将它们用作集合,所以也许我不应该使用数组,而要使用其他东西。

php arrays comparison set
5个回答
7
投票

接受的答案错误。它will将失败:https://3v4l.org/U8U5p

$a = ['x' => 1, 'y' => 2]; $b = ['x' => 1, 'y' => 1];

这里是正确的解决方案:

function consistsOfTheSameValues(array $a, array $b)
{
    // check size of both arrays
    if (count($a) !== count($b)) {
        return false;
    }

    foreach ($b as $key => $bValue) {

        // check that expected value exists in the array
        if (!in_array($bValue, $a, true)) {
            return false;
        }

        // check that expected value occurs the same amount of times in both arrays
        if (count(array_keys($a, $bValue, true)) !== count(array_keys($b, $bValue, true))) {
            return false;
        }

    }

    return true;
}

加上相当广泛的单元测试:https://3v4l.org/m6lHv

<?php

// A unit testing framework in a tweet. https://gist.github.com/mathiasverraes/9046427
function it($m,$p){echo ($p?'✔︎':'✘')." It $m\n"; if(!$p){$GLOBALS['f']=1;}}function done(){if(@$GLOBALS['f'])die(1);}

function consistsOfTheSameValues(array $a, array $b)
{
    // check size of both arrays
    if (count($a) !== count($b)) {
        return false;
    }

    foreach ($b as $key => $bValue) {

        // check that expected value exists in the array
        if (!in_array($bValue, $a, true)) {
            return false;
        }

        // check that expected value occurs the same amount of times in both arrays
        if (count(array_keys($a, $bValue, true)) !== count(array_keys($b, $bValue, true))) {
            return false;
        }

    }

    return true;
}

it('consist of the same values',
    consistsOfTheSameValues([1], [1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues([1, 1], [1, 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['1', 1], ['1', 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['1', 1], [1, '1']) === true
);

it('consist of the same values',
    consistsOfTheSameValues([1, '1'], ['1', 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues([1, '1'], [1, '1']) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['x' => 1], ['x' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['x' => 1], ['y' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['y' => 1], ['x' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['x' => 1, 'y' => 1], ['x' => 1, 'y' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['y' => 1, 'x' => 1], ['x' => 1, 'y' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['x' => 1, 'y' => 1], ['y' => 1, 'x' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['y' => 1, 'x' => 1], ['y' => 1, 'x' => 1]) === true
);

it('consist of the same values',
    consistsOfTheSameValues(['x' => 2, 'y' => 1], ['x' => 1, 'y' => 2]) === true
);

it('does not consist of the same values',
    consistsOfTheSameValues([1], [2]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1'], [1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1], ['1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1], [1, 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, 1], [1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1', 1], [1, 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, '1'], [1, 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, 1], ['1', 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, 1], [1, '1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1', '1'], [1, 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1', '1'], ['1', 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1', '1'], [1, '1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, 1], ['1', '1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['1', 1], ['1', '1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues([1, '1'], ['1', '1']) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['x' => 1], ['x' => 2]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['x' => 1, 'y' => 1], ['x' => 1, 'y' => 2]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['x' => 1, 'y' => 1], ['x' => 2, 'y' => 1]) === false
);

it('does not consist of the same values',
    consistsOfTheSameValues(['x' => 2, 'y' => 1], ['x' => 1, 'y' => 1]) === false
);

@@ update:

@ ircmaxell答案的广泛单元测试:https://3v4l.org/5ivgm

@ Jon anwser的广泛单元测试:https://3v4l.org/CrTgQ


12
投票

嗯,我们可以做这样的事情:

if (count(array_diff(array_merge($a, $b), array_intersect($a, $b))) === 0) {
    //they are the same!
}

它起作用的原因是,array_merge将创建一个大数组,同时包含array_merge$a的所有元素($b$a或两者中的所有元素) 。 $b将创建一个仅包含array_intersectarray_intersect中所有元素的数组。因此,如果它们不同,则必须至少有一个元素未同时出现在两个数组中...

还请注意,$a不是实际的函数/构造,它是别名。我建议使用$b来简化说明...


4
投票

接受的答案无法说明重复项。这是我的看法

sizeof

3
投票

如果您将数组视为集合

然后您的方法几乎是正确的(您需要删除元素计数的相等性测试)。

如果数组包含同一元素的多个副本很重要

那么您的方法是not正确的。您需要使用sizeof对数组进行排序,然后将其与count()进行比较。这应该更快,因为它可以在看到一个差异时中止比较而无需遍历整个数组。

更新:

[明确说明了OP的方法何时正确或不正确,并在此加入了public function sameElements($a, $b) { sort($a); sort($b); return $a == $b; } 可能比sort更好的建议。


2
投票

为了您的娱乐,我将添加一个示例来说明您的条件不正确:

sort

===

我建议使用其他模型。也许将元素添加为数组的键,但这只有在它们是整数或字符串的情况下才有可能。

sort

这将强制唯一性。使用此模型,您可以在asort上使用您的条件。

© www.soinside.com 2019 - 2024. All rights reserved.