PHP比较数组

34

有没有任何一种内置函数可以比较 PHP 中的数组,而不需要进行循环之类的操作?

$a1 = array(1,2,3);
$a2 = array(1,2,3);

if (array_are_same($a1, $a2)) {
    // code here
}

顺便说一下,数组值不总是按相同的顺序排列。


4
“the same”是什么意思?你的意思是它们包含相同的元素并且顺序也相同,还是只是它们包含相同的元素?如果是前者,karim79的答案是正确的;否则,提倡使用“ordinary ==”的答案就足够了。 - Rob
重复值怎么办? - hakre
最佳答案(最全面的)似乎是来自@hakre的答案:https://dev59.com/TnNA5IYBdhLWcg3wmfAa#17638939 << 在我看来,应该选择它作为正确的答案。 - Jon L.
18个回答

45
if ( $a == $b ) {
    echo 'We are the same!';
}

10
这也要求数组的键名也要匹配,就像在PHP文档中找到的数组比较示例一样:http://php.net/manual/en/language.operators.comparison.php - Jon L.
2
@JonL。if ( array_values( $a ) == array_values( $b ) {}?? - Eric Holmes
3
正如在另一个回答中的评论中所指出的,@EricHolmes提供的方法仅适用于顺序相同的情况:https://dev59.com/TnNA5IYBdhLWcg3wmfAa#901831?noredirect=1#comment19924354_901830 - Jon L.
1
查看问题的编辑历史记录,您将了解为什么答案符合于 2009年5月23日16:05 发布的原始问题。该问题是由其他人在 2013年7月14日11:43 进行编辑,以添加“顺便说一下,数组值不总是按相同顺序排列”。 - Alan Haggai Alavi

32

可以通过使用 array_diff() 在两个方向上比较两个数组是否具有相等的值(重复或不重复,考虑类型转换):

!array_diff($a, $b) && !array_diff($b, $a);

如果两个数组的值相同(经过类型转换后),则返回TRUE。否则返回FALSE。例如:

function array_equal_values(array $a, array $b) {
    return !array_diff($a, $b) && !array_diff($b, $a);
}

array_equal_values([1], []);            # FALSE
array_equal_values([], [1]);            # FALSE
array_equal_values(['1'], [1]);         # TRUE
array_equal_values(['1'], [1, 1, '1']); # TRUE

正如这个例子所示,array_diff 不考虑数组键的差异,也不关心值的顺序或是否重复。


如果重复项需要区分,这就变得更加棘手。就“简单”值而言(仅适用于字符串和整数值),array_count_values()可以收集有关数组中每个值出现次数的信息。这些信息可以轻松与 == 进行比较:

array_count_values($a) == array_count_values($b);

如果两个数组在类型转换后,对于同样的时间拥有相同的值,则返回TRUE。否则返回FALSE。例如:

function array_equal_values(array $a, array $b) {
    return array_count_values($a) == array_count_values($b);
}

array_equal_values([2, 1], [1, 2]);           # TRUE
array_equal_values([2, 1, 2], [1, 2, 2]);     # TRUE
array_equal_values(['2', '2'], [2, '2.0']);   # FALSE
array_equal_values(['2.0', '2'], [2, '2.0']); # TRUE

通过首先比较两个数组的计数(即值重复的情况下区分大部分数组的一种相对便宜且快速的测试),可以进一步优化此过程。


到目前为止,这些示例仅部分限于字符串和整数值,并且使用array_diff不能进行严格比较。更专门用于严格比较的是array_search。因此,需要对值进行计数和索引,以便它们可以作为键进行比较(就像array_search所做的那样)。

这需要更多的工作。 然而,最终的比较与之前相同:

$count($a) == $count($b);

只是$count的差异:

    $table = [];
    $count = function (array $array) use (&$table) {
        $exit   = (bool)$table;
        $result = [];
        foreach ($array as $value) {
            $key = array_search($value, $table, true);

            if (FALSE !== $key) {
                if (!isset($result[$key])) {
                    $result[$key] = 1;
                } else {
                    $result[$key]++;
                }
                continue;
            }

            if ($exit) {
                break;
            }

            $key          = count($table);
            $table[$key]  = $value;
            $result[$key] = 1;
        }

        return $result;
    };

这将保留一个数值表,以便两个数组可以使用相同的索引。同时,在第二个数组第一次遇到新值时,可以提前退出。

通过添加额外的参数,此函数还可以添加严格模式。通过再添加另一个额外的参数,则可以选择启用查找重复项或不启用。完整示例:

function array_equal_values(array $a, array $b, $strict = FALSE, $allow_duplicate_values = TRUE) {

    $add = (int)!$allow_duplicate_values;

    if ($add and count($a) !== count($b)) {
        return FALSE;
    }

    $table = [];
    $count = function (array $array) use (&$table, $add, $strict) {
        $exit   = (bool)$table;
        $result = [];
        foreach ($array as $value) {
            $key = array_search($value, $table, $strict);

            if (FALSE !== $key) {
                if (!isset($result[$key])) {
                    $result[$key] = 1;
                } else {
                    $result[$key] += $add;
                }
                continue;
            }

            if ($exit) {
                break;
            }

            $key          = count($table);
            $table[$key]  = $value;
            $result[$key] = 1;
        }

        return $result;
    };

    return $count($a) == $count($b);
}

使用示例:

array_equal_values(['2.0', '2', 2], ['2', '2.0', 2], TRUE);           # TRUE
array_equal_values(['2.0', '2', 2, 2], ['2', '2.0', 2], TRUE);        # TRUE
array_equal_values(['2.0', '2', 2, 2], ['2', '2.0', 2], TRUE, FALSE); # FALSE
array_equal_values(['2'], ['2'], TRUE, FALSE);                        # TRUE
array_equal_values([2], ['2', 2]);                                    # TRUE
array_equal_values([2], ['2', 2], FALSE);                             # TRUE
array_equal_values([2], ['2', 2], FALSE, TRUE);                       # FALSE

如果一个数组有两个相同的值,那么这个答案就不适用。而另一个数组也必须有这个值出现两次。 - Case
@Iscariot:确实是一个有趣的场景,但并未涵盖答案。最可能的答案是短路复制值比较,因为问题也没有涉及到这些内容。还有另一种可能的区分方式:重复(n次)值需要匹配n次或1:n次。 - hakre

13

@Cleanshooter,很抱歉这并没有实现预期的功能:(在此情况下提到的array_diff也是如此)

$a1 = array('one','two');
$a2 = array('one','two','three');

var_dump(count(array_diff($a1, $a2)) === 0); // returns TRUE

(注解:在 PHP 5.5 之前,您不能在函数上使用 empty ) 在这种情况下,结果为真,尽管数组不同。

array_diff [...] 返回一个数组,其中包含 array1 中所有未出现在任何其他数组中的条目。

这并不意味着 array_diff 就像是 array_get_all_differences。从数学集合的角度来解释,它计算的是:

{'one','two'} \ {'one','two','three'} = {}

这意味着第一个集合中的所有元素,除了第二个集合中也包含在第一个集合中的元素。因此,
var_dump(array_diff($a2, $a1));

计算为

array(1) { [2]=> string(5) "three" } 

结论是,你需要在“双向”上进行array_diff,以获取两个数组中的所有“差异”。希望这能帮到你 :)

5
您可以尝试以下方法:
if(serialize($a1) == serialize($a2))

3

只需检查$a1 == $a2--这有什么问题吗?


3
这也要求数组的键名匹配,就像在 PHP 文档中找到的数组比较示例一样:php.net/manual/en/language.operators.comparison.php。 - Jon L.
有了Jon L.的提示,我猜这是比较数组值的最佳方法:array_values($a1) == array_values($a2) - Tyron
...并且顺序必须相同。根据需要,您可能需要先对数组进行排序。 - NickSoft

3

2

以下是评论的结论:

仅比较数组值(进行类型转换后)是否相等且顺序相同:

array_values($a1) == array_values($a2)

比较数组值(在类型转换后)是否相等并且顺序相同,以及数组键是否相同且顺序相同:

array_values($a1) == array_values($a2) && array_keys($a1) == array_keys($a2)

3
哇,我从 C++ 转向 PHP。差别很大。在 PHP 中,最合适的答案被埋藏在五屏幕的“嗯,这个东西怎么样?”之下。而在 C++ 中,我看到的只有“嗯,从技术上讲,最正确的答案必须是这个!”。 - Scott
如果你只是想比较两个键和值,为什么不使用 $a1 == $a2 呢? - NickSoft

1
从用户获取数组或输入数组值。使用sort函数对两个数组进行排序。使用三元运算符检查。如果两个数组相等,它将打印“数组相等”,否则它将打印“数组不相等”。这里没有循环迭代。
sort($a1);
sort($a2);
echo (($a1==$a2) ? "arrays are equal" : "arrays are not equal");

1
这种确切的方式已经在另一个答案中被建议过了,重复一遍真的没有什么意义。 - Shadow The Spring Wizard

1

一种快速比较任意顺序数组值的方法...

function arrays_are_same($array1, $array2) {
    sort($array1);
    sort($array2);
    return $array1==$array2;
}

So for...

    $array1 = array('audio', 'video', 'image');
    $array2 = array('video', 'image', 'audio');

arrays_are_same($array1, $array2) 将返回 TRUE


数组的顺序并不重要,根据http://php.net/manual/en/language.operators.comparison.php上的示例#1。 - Tyron
如果您执行 var_dump(array(1,2,3) == array(3,2,1));,则会得到 bool(false)。同样的情况也适用于示例 #1:var_dump(standard_array_compare(array(1,2,3), array(3,2,1))); 返回 int(-1) - chichilatte

1
如果您想在一个包含大量数组(>10k)的大数组中搜索某些数组,则比较序列化数组(保存在缓存中)会更快。以下是使用URL的示例:
/**
@return array
*/
function createCache()
{
    $cache = [];
    foreach ($this->listOfUrl() as $url => $args)
    {
        ksort($args);
        $cache['url'][$url] = $args;
        $cache['arr'][crc32(serialize($args))] = $url;
    }
    return $cache;
}

/**
@param array $args
@return string
*/
function searchUrl($args)
{
    ksort($params);
    $crc = crc32(serialize($params));        
    return isset($this->cache['arr'][$crc]) ? $this->cache['arr'][$crc] : NULL;                
} 

/**
@param string $url
@return array
*/
function searchArgs($url)
{
    return isset($this->cache['url'][$url]) ? $this->cache['url'][$url] : NULL;
}

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