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

2015-01-24信息快讯网
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 ob_start()控制浏览器cache、生成html实现代码
Zend framework处理一个http请求的流程分析
PHP编程过程中需要了解的this,self,parent的区别
PHP array_push 数组函数
php smarty模版引擎中变量操作符及使用方法
php smarty模版引擎中的缓存应用
php array_map array_multisort 高效处理多维数组排序
PHP加速 eAccelerator配置和使用指南
mysql_fetch_row,mysql_fetch_array,mysql_fetch_assoc的区别
php array_flip() 删除数组重复元素
php array_intersect()函数使用代码
PHP setcookie() cannot modify header information 的解决方法
Cannot modify header information错误解决方法
php格式化工具Beautify PHP小小BUG
php出现Cannot modify header information问题的解决方法大全
PHP 实例化类的一点摘记
附件名前加网站名
由php if 想到的些问题
asp和php下textarea提交大量数据发生丢失的解决方法
Http 1.1 Etag 与 Last-Modified提高php效率
使用 eAccelerator加速PHP代码的方法
实现php加速的eAccelerator dll支持文件打包下载
用windows下编译过的eAccelerator for PHP 5.1.6实现php加速的使用方法
PHP5中的this,self和parent关键字详解教程
PHP编码规范-php coding standard
使用 eAccelerator加速PHP代码的目的
Smarty+QUICKFORM小小演示
excellent!――ASCII Art(由目标图象生成ascii)
mysql_fetch_assoc和mysql_fetch_row的功能加起来就是mysql_fetch_array
介绍几个array库的新函数 php
动态生成gif格式的图像要注意?
让你的PHP同时支持GIF、png、JPEG
模拟SQLSERVER的两个函数:dateadd(),datediff()
©2014-2024 dbsqp.com