PHP数组交集的优化代码分析

 更新时间:2011年03月06日 21:55:10   作者:  
假设我们正在运营一个手机相关的网站,用户可以通过指定若干参数(如操作系统,屏幕分辨率,摄像头像素等等)来筛选自己想要的手机。
不过由于手机的参数多,且不同的手机其参数差异大,所以参数表结构通常是纵表(一个参数是一行),而不是横表(一个参数是一列),此时使用若干参数来取结果,通常就是把每个单独参数来取结果,再一起取交集。
假定每个参数会包含一千个左右的唯一结果(id int),以此为前提来模拟生成一些数据:
复制代码 代码如下:

<?php
$rand = function() {
$result = array();
for ($i = 0; $i < 1000; null) {
$value = mt_rand(1, 10000);
if (!isset($result[$value])) {
$result[$value] = null;
$i++;
}
}
return array_keys($result);
};
$param_a = $rand();
$param_b = $rand();
?>

注意:如果测试数据集过小的话,结论可能会出现不一致,先来看看通过PHP内置方法array_intersect实现的性能:
复制代码 代码如下:

<?php
$time = microtime(true);
$result = array_intersect($param_a, $param_b);
$time = microtime(true) - $time;
echo "array_intersect: {$time}\n";
?>

再来看看通过自定义方法intersect实现的性能:
复制代码 代码如下:

<?php
function intersect() {
if (func_num_args() < 2) {
trigger_error('param error', E_USER_ERROR);
}
$args = func_get_args();
foreach ($args AS $arg) {
if (!is_array($arg)) {
trigger_error('param error', E_USER_ERROR);
}
}
$intersect = function($a, $b) {
$result = array();
$length_a = count($a);
$length_b = count($b);
for ($i = 0, $j = 0; $i < $length_a && $j < $length_b; null) {
if($a[$i] < $b[$j]) {
$i++;
} else if($a[$i] > $b[$j]) {
$j++;
} else {
$result[] = $a[$i];
$i++;
$j++;
}
}
return $result;
};
$result = array_shift($args);
sort($result);
foreach ($args as $arg) {
sort($arg);
$result = $intersect($result, $arg);
}
return $result;
}
$time = microtime(true);
$result = intersect($param_a, $param_b);
$time = microtime(true) - $time;
echo "intersect: {$time}\n";
?>

直觉上,我们肯定会认为内置函数快于自定义函数,但本例中结果恰恰相反:
array_intersect: 0.023918151855469
intersect: 0.0026049613952637
需要提醒大家的是,array_intersect和intersect在功能上并不完全等价,例子如下:
复制代码 代码如下:

$param_a = array(1, 2, 2);
$param_b = array(1, 2, 3);
var_dump(
array_intersect($param_a, $param_b),
intersect($param_a, $param_b)
);

array_intersect: 1, 2, 2
intersect: 1, 2
也就是说,如果在第一个数组参数中有重复元素的话,则array_intersect会返回所有满足条件的重复元素,而不是仅仅返回一个,有兴趣的读者可以变换一下参数顺序再看结果。
再唠叨一下,最初我写intersect方法时,大概写成下面这个样子:
复制代码 代码如下:

<?php
function intersect() {
if (func_num_args() < 2) {
trigger_error('param error', E_USER_ERROR);
}
$args = func_get_args();
foreach ($args AS $arg) {
if (!is_array($arg)) {
trigger_error('param error', E_USER_ERROR);
}
}
$result = array();
$data = array_count_values(
call_user_func_array('array_merge', $args)
);
foreach ($data AS $value => $count) {
if ($count > 1) {
$result[] = $value;
}
}
return $result;
}
?>

代码更简洁,不过有一个弊端,因为使用了array_merge,所以当数组中元素非常多的时候,占用的内存会比较大,反之如果数组中元素不是非常多,那么此方法也是可行的。(来源:火丁笔记)

相关文章

  • PHP实现删除多重数组对象属性并重新赋值的方法

    PHP实现删除多重数组对象属性并重新赋值的方法

    这篇文章主要介绍了PHP实现删除多重数组对象属性并重新赋值的方法,涉及php结合sphinx操作数组元素的相关实现技巧,需要的朋友可以参考下
    2017-06-06
  • PHP随机生成随机个数的字母组合示例

    PHP随机生成随机个数的字母组合示例

    在很多系统环境下大家都会用到字母组合各种编码。下面为大家介绍下使用php随机生成随机个数的字母组合,感兴趣的朋友可以了解下
    2014-01-01
  • 访问编码后的中文URL返回404错误的解决方法

    访问编码后的中文URL返回404错误的解决方法

    这篇文章主要介绍了访问编码后的中文URL返回404错误的解决方法,本文使用的是替换方法,当然也可以使用加密方法来解决,最后附妹子图一张,需要的朋友可以参考下
    2014-08-08
  • PHP+iframe模拟Ajax上传文件功能示例

    PHP+iframe模拟Ajax上传文件功能示例

    这篇文章主要介绍了PHP+iframe模拟Ajax上传文件功能,结合实例形式分析了iframe模拟Ajax上传文件与后台php接收处理相关操作技巧,需要的朋友可以参考下
    2019-07-07
  • 总结对比php中的多种序列化

    总结对比php中的多种序列化

    序列化是将变量转换为可保存或传输的字符串的过程;反序列化就是在适当的时候把这个字符串再转化成原来的变量使用。这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性。下面来看php中多种序列化的对比。
    2016-08-08
  • php计算指定目录下文件占用空间的方法

    php计算指定目录下文件占用空间的方法

    这篇文章主要介绍了php计算指定目录下文件占用空间的方法,实例分析了php操作目录及文件的技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-03-03
  • PHP文件缓存类实现代码

    PHP文件缓存类实现代码

    这篇文章主要介绍了PHP文件缓存类实现代码,php中缓存分类数据库缓存,文件缓存和内存缓存,对php缓存感兴趣的朋友可以学习学习下面的文章。
    2015-10-10
  • PHP实现提取多维数组指定一列的方法总结

    PHP实现提取多维数组指定一列的方法总结

    这篇文章主要介绍了PHP实现提取多维数组指定一列的方法,结合实例形式总结分析了PHP针对多维数组的遍历、转换、提取等相关操作技巧,需要的朋友可以参考下
    2019-12-12
  • PHP开发中常用的8个小技巧

    PHP开发中常用的8个小技巧

    PHP日常开发中常用的8个小技巧。简单实用
    2008-08-08
  • php生成excel文件的简单方法

    php生成excel文件的简单方法

    生成excel文件,最简单的莫过于把数据库的数据导入到excel就行了,下面有个不错的示例,大家可以参考下
    2014-02-02

最新评论