深思 PHP 数组遍历的差异(array_diff 的实现)


Posted in PHP onMarch 23, 2008

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 函数需要循环判断是否在函数内;而函数三则仅仅判断这个数组是否存在该键就可以了。加上数组键和值不同的组织索引方式,效率比想象的还高那就非常可以理解了。

附代码

<?php 
function microtime_float() { 
    list($usec, $sec) = explode(" ", microtime()); 
    return ((float)$usec + (float)$sec); 
} function array_diff2($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_diff3($array_1, $array_2) { 
    foreach ($array_1 as $key => $item) { 
        if (in_array($item, $array_2, true)) { 
            unset($array_1[$key]); 
        } 
    } 
    return $array_1; 
} 

function array_diff4($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; 
} 
////////////////////////////// 
for($i = 0, $ary_1 = array(); $i < 5000; $i++) { 
    $ary_1[] = rand(100, 999); 
} 
for($i = 0, $ary_2 = array(); $i < 5000; $i++) { 
    $ary_2[] = rand(100, 999); 
} 
header("Content-type: text/plain;charset=utf-8"); 
$time_start = microtime_float(); 
array_diff($ary_1, $ary_2); 
echo "函数 array_diff 运行" . (microtime_float() - $time_start) . " 秒\n"; 
$time_start = microtime_float(); 
array_diff2($ary_1, $ary_2); 
echo "函数 array_diff2 运行" . (microtime_float() - $time_start) . " 秒\n"; 
$time_start = microtime_float(); 
array_diff3($ary_1, $ary_2); 
echo "函数 array_diff3 运行" . (microtime_float() - $time_start) . " 秒\n"; 
$time_start = microtime_float(); 
array_diff4($ary_1, $ary_2); 
echo "函数 array_diff4 运行" . (microtime_float() - $time_start) . " 秒\n"; 
?>

PHP 相关文章推荐
PHP5/ZendEngine2的改进
Oct 09 PHP
Zend Studio 无法启动的问题解决方法
Dec 04 PHP
PHP is_dir() 判断给定文件名是否是一个目录
May 10 PHP
php 中的4种标记风格介绍
May 10 PHP
php设计模式小结
Feb 15 PHP
使用PHP编写的SVN类
Jul 18 PHP
php获取新浪微博数据API实例
Nov 12 PHP
ThinkPHP3.1的Widget新用法
Jun 19 PHP
thinkphp框架实现删除和批量删除
Jun 29 PHP
php获取微信共享收货地址的方法
Dec 21 PHP
PHP实现基于状态的责任链审批模式详解
May 31 PHP
浅谈php常用的7大框架的优缺点
Jul 20 PHP
附件名前加网站名
Mar 23 #PHP
由php if 想到的些问题
Mar 22 #PHP
php实现mysql数据库备份类
Mar 20 #PHP
php 常用字符串函数总结
Mar 15 #PHP
php str_replace的替换漏洞
Mar 15 #PHP
PHP执行速率优化技巧小结
Mar 15 #PHP
请php正则走开
Mar 15 #PHP
You might like
关于手调机和数调机的选择
2021/03/02 无线电
第九节 绑定 [9]
2006/10/09 PHP
php中根据变量的类型 选择echo或dump
2012/07/05 PHP
JAVASCRIPT keycode总结
2009/02/04 Javascript
AJAX 网页保留浏览器前进后退等功能
2011/02/12 Javascript
加载远程图片时,经常因为缓存而得不到更新的解决方法(分享)
2013/06/26 Javascript
JavaScript String 对象常用方法详解
2016/05/13 Javascript
Javascript字符串常用方法详解
2016/07/21 Javascript
JS版微信6.0分享接口用法分析
2016/10/13 Javascript
谈谈JS中常遇到的浏览器兼容问题和解决方法
2016/12/17 Javascript
微信小程序 新建登录页并实现tabBar隐藏
2017/06/13 Javascript
详解JS数据类型的值拷贝函数(深拷贝)
2017/07/13 Javascript
jQuery pjax 应用简单示例
2018/09/20 jQuery
JS实现水平遍历和嵌套递归操作示例
2019/08/15 Javascript
浅谈监听单选框radio改变事件(和layui中单选按钮改变事件)
2019/09/10 Javascript
js脚本中执行java后台代码方法解析
2019/10/11 Javascript
在vs code 中如何创建一个自己的 Vue 模板代码
2020/11/10 Javascript
[01:06:43]完美世界DOTA2联赛PWL S3 PXG vs GXR 第二场 12.19
2020/12/24 DOTA
Python常用随机数与随机字符串方法实例
2015/04/09 Python
举例讲解Python的Tornado框架实现数据可视化的教程
2015/05/02 Python
Python iter()函数用法实例分析
2018/03/17 Python
Python反转序列的方法实例分析
2018/03/21 Python
Python实现读写INI配置文件的方法示例
2018/06/09 Python
Django之提交表单与前后端交互的方法
2019/07/19 Python
Python字典推导式将cookie字符串转化为字典解析
2019/08/10 Python
Python如何操作docker redis过程解析
2020/08/10 Python
印尼穆斯林时尚购物网站:Hijabenka
2016/12/10 全球购物
Mamas & Papas沙特阿拉伯:英国最受欢迎的婴儿品牌
2017/11/20 全球购物
计算机通信工程专业毕业生推荐信
2013/12/24 职场文书
求职者怎样写自荐信
2014/04/13 职场文书
经典演讲稿开场白
2014/08/25 职场文书
总经理检讨书
2014/09/15 职场文书
大学生联谊活动策划书(光棍节)
2014/10/10 职场文书
道歉信怎么写
2015/05/12 职场文书
游戏开发中如何使用CocosCreator进行音效处理
2021/04/14 Javascript
解决使用了nginx获取IP地址都是127.0.0.1 的问题
2021/09/25 Servers