假设我们正在运营一个手机相关的网站,用户可以通过指定若干参数(如操作系统,屏幕分辨率,摄像头像素等等)来筛选自己想要的手机。不过由于手机的参数多,且不同的手机其参数差异大,所以参数表结构通常是纵表(一个参数是一行),而不是横表(一个参数是一列),此时使用若干参数来取结果,通常就是把每个单独参数来取结果,再一起取交集。
假定每个参数会包含一千个左右的结果,以此为前提来模拟生成一些数据:
以下是代码片段:
<?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()) {
trigger_error(’param error’, E_USER_ERROR);
}
foreach (func_get_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’, func_get_args())
);
foreach ($data AS $value => $count) {
if ($count > 1) {
$result[] = $value;
}
}
return $result;
}
$time = microtime(true);
$result = intersect($param_a, $param_b);
$time = microtime(true) - $time;
echo "intersect: {$time}\n";
?>
注:如果数组元素的数量很大的话,array_merge的时候可能会溢出。
直觉上,我们肯定会认为内置函数快于自定义函数,但本例中结果恰恰相反:
- 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会返回所有满足条件的重复元素,而不是仅仅返回一个,有兴趣的读者可以变换一下参数顺序再看结果。
实际使用中,很多情况下我们都能保证数组参数没有重复元素,交集其实就是求合并数组中元素数量大于一的集合,此时在速度上array_intersect就显得鸡肋了。