深思 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 相关文章推荐
用PHP函数解决SQL injection
Oct 09 PHP
超级简单的发送邮件程序
Oct 09 PHP
在WAMP环境下搭建ZendDebugger php调试工具的方法
Jul 18 PHP
PHP 多维数组的排序问题 根据二维数组中某个项排序
Nov 09 PHP
PHP 之Section与Cookie使用总结
Sep 14 PHP
PHP 提取图片img标记中的任意属性的简单实例
Dec 10 PHP
php实现过滤字符串中的中文和数字实例
Jul 29 PHP
标准版Eclipse搭建PHP环境的详细步骤
Nov 18 PHP
php自动加载方式集合
Apr 04 PHP
初识ThinkPHP控制器
Apr 07 PHP
Symfony2获取web目录绝对路径、相对路径、网址的方法
Nov 14 PHP
PHP中$GLOBALS与global的区别详解
Mar 21 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
星际中一些鲜为人知的详细资料
2020/03/04 星际争霸
使用php+xslt在windows平台上
2006/10/09 PHP
php 智能404跳转代码,适合换域名没改变目录的网站
2010/06/04 PHP
学习php设计模式 php实现工厂模式(factory)
2015/12/07 PHP
php 基础函数
2017/02/10 PHP
thinkPHP5分页功能实现方法分析
2017/10/25 PHP
PHP实现的一致性Hash算法详解【分布式算法】
2018/03/31 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
JavaScript中也使用$美元符号来代替document.getElementById
2010/06/19 Javascript
iframe窗口高度自适应的又一个巧妙实现思路
2014/04/04 Javascript
JavaScript字符串对象toUpperCase方法入门实例(用于把字母转换为大写)
2014/10/17 Javascript
jQuery及JS实现循环中暂停的方法
2015/02/02 Javascript
JavaScript创建一个object对象并操作对象属性的用法
2015/03/23 Javascript
jquery实现先淡出再折叠收起的动画效果
2015/08/07 Javascript
node.js中 stream使用教程
2016/08/28 Javascript
详解Vue 非父子组件通信方法(非Vuex)
2017/05/24 Javascript
在 Angular-cli 中使用 simple-mock 实现前端开发 API Mock 接口数据模拟功能的方法
2018/11/28 Javascript
jQuery模拟html下拉多选框的原生实现方法示例
2019/05/30 jQuery
layui添加动态菜单与选项卡
2019/07/26 Javascript
从零撸一个pc端vue的ui组件库( 计数器组件 )
2019/08/08 Javascript
详解Vue之计算属性
2020/06/20 Javascript
JavaScript实现简易计算器小功能
2020/10/22 Javascript
vue created钩子函数与mounted钩子函数的用法区别
2020/11/05 Javascript
简单介绍Python中的readline()方法的使用
2015/05/24 Python
Python计算三维矢量幅度的方法
2015/06/15 Python
python中报错&quot;json.decoder.JSONDecodeError: Expecting value:&quot;的解决
2019/04/29 Python
Python如何脚本过滤文件中的注释
2020/05/27 Python
利用Opencv实现图片的油画特效实例
2021/02/28 Python
基于Html5实现的语音搜索功能
2019/05/13 HTML / CSS
GLAMGLOW格莱魅美国官网:美国知名的面膜品牌
2016/12/31 全球购物
澳大利亚音乐商店:Bava’s Music City
2019/05/05 全球购物
Lentiamo荷兰:在线订购隐形眼镜、隐形眼镜液和太阳镜
2019/10/25 全球购物
接口可以包含哪些成员
2012/09/30 面试题
个人生活学习自我评价范文
2013/11/26 职场文书
2015年青年教师工作总结
2015/05/25 职场文书
nginx七层负载均衡配置详解
2022/07/15 Servers