首页 | 新闻 | 交流 | 问吧 | 文档 | 手册 | 下载 | 博客

收藏此问题 发表新评论

【原创】深思 PHP 数组遍历的差异(array_diff 的实现)

原文链接: http://www.gracecode.com/Archive/Display/421

还是部门无聊的考题,不过这次考的是 PHP 的能力。题目如下:

给你两个分别有 5000 个元素的数组,计算他们的差集
  -- 说白了也就是用 PHP 和你认为最好的算法实现 array_diff 的算法。

初次接到这个题目,我发现这非常的简单,于是按照以往的经验“随便”写了一个:

function array_diff($array_1, $array_2) {
    $diff = array();

    foreach ($array_1 as $k => $v1) {
        $flag = false;
        foreach ($array_2 as $v2) {
            if ($flag = ($v1 == $v2)) {
                break;
            }
        }

        if (!$flag) {
            $diff[$k] = $v1;
        }
    }

    return $diff;
}

虽然实现是可以的,但是发现这个函数的效率是惨不忍睹。于是我又重新考虑了下,并优化了算法,第二个函数看起来是这个样子的:


function array_diff($array_1, $array_2) {
    foreach ($array_1 as $key => $item) {
        if (in_array($item, $array_2, true)) {
            unset($array_1[$key]);
        }
    }

    return $array_1;
}

嗯,这次几乎可以和原 array_diff 函数的速度媲美了。但是还有没有更优化的办法呢?由 ChinaUnix 上的一篇文章(不好意思,作弊了),我发现 PHP 竟然可以这样写:

function array_diff($array_1, $array_2) {
    $array_2 = array_flip($array_2);
    foreach ($array_1 as $key => $item) {
        if (isset($array_2[$item])) {
            unset($array_1[$key]);
        }
     }

    return $array_1;
}

这个函数的效率非常的惊人,甚至比原 array_diff 函数的速度都要快。究其原因,我找到了解释:

因为键是进行 HASH 组织的,查找很快;
而 Value 只是由 Key 组织存放,本身没有索引,每次查找都是遍历。

总结

这虽然是 PHP 语言的一个小窍门,但在遍历和对比数组的值上,如果需要对比值将其与键反转的确比通常的值对值的比较效率要高得多。

比如,上面的函数二需要调用 in_array 函数需要循环判断是否在函数内;而函数三则仅仅判断这个数组是否存在该键就可以了。

加上数组键和值不同的组织索引方式,效率比想象的还高那就非常可以理解了。

附,下载链接和脚本:http://www.gracecode.com/Archive/Display/421
昵称: amdk6  时间: 2007-12-21 12:51:00
array_flip厉害,又学到了,以前还没看过这个函数!
昵称: PHPChina  时间: 2007-12-21 13:32:00
学习了~
昵称: zhaofei299  时间: 2007-12-26 10:42:00
不知道楼主有没有测试过后两个方法的速度呢?

既然key是有索引的,那array_flip的效率有多高呢?

不过转换一次以后就不用每次找值了
昵称: airwin  时间: 2008-01-16 12:20:00
鼓励!
昵称: 芽雨  时间: 2008-01-16 12:37:00
if (isset($array_2[$item])) {
        unset($array_1[$key]);
}

这个能做匹配用么 ?
昵称: luzhou  时间: 2008-01-17 15:22:00
我也写了一个版,呵呵

<?php
$array1 = array('blue','red','yellow','white');
$array2 = array('blue','white');

function my_array_differ($arr1,$arr2){
        $arr = array();
        foreach ($arr1 as $v){
                if (!in_array($v, $arr2)){
                        $arr[] = $v;
                }
        }
        return $arr;
}

$arr_result = my_array_differ($array1,$array2);
print_r($arr_result)
?>
昵称: ct_174880859  时间: 2008-01-29 10:58:00
又学了一招啊。。。
昵称: 深蓝色  时间: 2008-03-21 10:31:00
第一次发现原来数组索引的命名规则跟变量是不同的,我一直以为是一样的呢。
昵称: zhnv  时间: 2008-05-08 12:56:00