IT技术博客大学习 共学习 共进步

PHP数组交集的优化

火丁笔记 2011-01-30 03:25:15 浏览 2,682 次

假设我们正在运营一个手机相关的网站,用户可以通过指定若干参数(如操作系统,屏幕分辨率,摄像头像素等等)来筛选自己想要的手机。不过由于手机的参数多,且不同的手机其参数差异大,所以参数表结构通常是纵表(一个参数是一行),而不是横表(一个参数是一列),此时使用若干参数来取结果,通常就是把每个单独参数来取结果,再一起取交集。

假定每个参数会包含一千个左右的结果,以此为前提来模拟生成一些数据:

以下是代码片段:
<?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就显得鸡肋了。

建议继续学习

  1. 为什么数组标号是从0开始的? (阅读 6,164)
  2. C语言结构体里的成员数组和指针 (阅读 6,083)
  3. 将数组定义为常量 (阅读 5,544)
  4. Tips of Linux C programming (阅读 5,104)
  5. xml转数组的方法 (阅读 4,584)
  6. 一个 VLA (可变长度数组)的实现 (阅读 4,187)
  7. javascript扩展Array(数组)类 (阅读 4,102)
  8. php数组排序 (阅读 4,085)
  9. 动态数组的 C 实现 (阅读 4,003)
  10. javascript数组排序的问题 (阅读 3,844)