世界杯以来,可用分输了不少,爆冷的时候,我稳了,我想爆冷,南非那稳住了,心情极度郁闷,散个200分,希望能让我输到世界杯结束上周做的一个测试,现在匆匆忙忙加了几行注释,发出来,因为皮厚,又戴着深度眼镜,也就不怕贻笑大方了有蛮长一段时间,我都用foreach,in_array,array_search来查找数组中的元素,直觉觉得,系统提供的,都是及其优化后的方案,一直到之前遇到了一些问题。深刻体会到具体问题具体分析的概念下面用了几种常用的判断方法,来检测数组中是否含有某一个元素,过程不说了,有兴趣的一看便知。路过的朋友,若愿意测试,请把测试结果贴上来也希望路过的朋友提供更优的方案,贴在下面,不胜感激set_time_limit(0);$arr = array();//测试数组$arrLength = 5000;//测试数组长度$arrType = 2;//1是1—1亿随机数字,2是8位字符串,3是32位字符串$cycleTimes = 100;//测试次数,尽量避免偶然情况$searchTimes = 50;//查找次数实际是50*2,50个能找到,50个找不到$keywordArr = array();//要比对的元素,数组形式保存$resultArr = array();//记录测试结果的数组/**
 * 构造数组元素
 *
 * @access  public
 * @param   integer $arrType 元素类型
 * @param   bool $flag 为了构造差异元素
 * @return  string
 */
function creatItem($arrType = 1, $flag = true)
{
$item = '';
$seed = $flag ? rand(1, 50000000) : rand(50000001, 100000000);
switch($arrType)
{
case 1:
$item =  $seed;
break;
case 2:
$item = sprintf('%X', crc32($seed));
break;
default:
$item = md5($seed);
}
return $item;
}//测试数组赋值,同时保存$searchTimes个能找到的元素
for($i=0;$i<$arrLength;$i++)
{
$arr[] = creatItem($arrType, true);
if($i < $searchTimes)
{
$keywordArr[] = $arr[$i];
}
}//构造$searchTimes个测试数组中没有的值
for($i=0;$i<$searchTimes;$i++)
{
$keywordArr[] = creatItem($arrType, false);
}/*********************初始化结束*****************///每种方法测,都用到shuffle,所以这里顺便测试一下效率
$timeStart = gettimeofday();
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
}
$resultArr['shuffle'] = gettimeofday();//开始循环测试foreach
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
foreach($keywordArr AS $v)
{
foreach($arr AS $value)
{
if($value == $v)
{
break;
}
}
}
}
$resultArr['foreach'] = gettimeofday();//开始循环测试in_array
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
foreach($keywordArr AS $v)
{
in_array($v, $arr);
}
}
$resultArr['in_array'] = gettimeofday();//开始循环测试array_search
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
foreach($keywordArr AS $v)
{
array_search($v, $arr);
}
}
$resultArr['array_search'] = gettimeofday();//开始循环测试strpos
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
$arraystring = ',' . implode(',', $arr) . ',';
foreach($keywordArr AS $v)
{
strpos($arraystring, ',' . $v . ',');
}
}
$resultArr['strpos'] = gettimeofday();//开始循环测试array_key_exists
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
$arr = array_flip($arr);
foreach($keywordArr AS $v)
{
array_key_exists($v, $arr);
}
}
$resultArr['array_key_exists'] = gettimeofday();//开始循环测试isset($arr[$key])
for($i=0;$i<$cycleTimes;$i++)
{
shuffle($arr);
$arr = array_flip($arr);
foreach($keywordArr AS $v)
{
isset($arr[$v]);
}
}
$resultArr['isset_key'] = gettimeofday();//打印结果
echo var_dump($arrLength, $arrType, $cycleTimes, $searchTimes) . '<br />';
foreach($resultArr AS $k => $v)
{
$time = ($v["usec"]-$timeStart["usec"])/1000000+$v["sec"]-$timeStart["sec"];
$time = round($time, 6)."秒";
echo $time . ' ' . $k . '<br />';
$timeStart = $v;
}

解决方案 »

  1.   

    我觉得还可以加上用数组的键查找ex:$arr[$element]
      

  2.   


    我贴的后面两种,是将元素key value交换,并判断key是否存在,,,当然因为效率测下来,两种还是有一点点差异的,所以凑数,就分为了2种你说的键查找,能否详细说?
      

  3.   

    如果需要按值查找,那么应该维护两份数据,
    一份是key=>value,一份是value=>key, 这样查找就很快了.
    搜索值是很慢的,但是搜索键很快,因为数组都是hash表,
    0,1,2,3等下标直接截断作为hash中的下标,
    字符串下标是用time33算法映射到整数下标的.
      

  4.   

    直接array_flip()就可以了,楼主也用了
      

  5.   


    我的需求,只需判定是否存在,所以数组恢复这个就省了,因为有个array_flip,当比对次数很少的时候,还是不要用的好
      

  6.   

    因为key必须唯一,就使得array_flip会丢失重复的元素【保留一个】
      

  7.   

    我看php的方法都给你总结得差不多了,呵呵。
    如果是我,碰到大数组的情况,一般会考虑牺牲空间,在$arr生成的时候构建一个索引表。其实和array_flip一样。
    ...
    //测试数组赋值,同时保存$searchTimes个能找到的元素
    for($i=0;$i<$arrLength;$i++)
    {
        $arr[$i]    =  $rvalue = creatItem($arrType, true);
        $hash[$rvalue][] = $i;//...
        if($i < $searchTimes)
        {
            $keywordArr[]    = $arr[$i];
        }
    }
    ..for($i=0;$i<$cycleTimes;$i++)
    {
        shuffle($arr);
    foreach($keywordArr AS $v) isset($hash[$v]);
    }
    $resultArr['hash']    = gettimeofday();
      

  8.   

    int(5000) int(2) int(100) int(50) 
    0.041007秒 shuffle
    11.698075秒 foreach
    8.002122秒 in_array
    7.986511秒 array_search
    2.050716秒 strpos
    0.237464秒 array_key_exists
    0.22903秒 isset_key
      

  9.   

    虽然说跟array_flip原理差不多,但的确受到启发了……另外,我贴的代码有些问题,不知道有人看出来没有……我本地测试的没有,为了整齐,我修改了一些变量,画蛇添足了
      

  10.   

    array_flip性能很低, 每次判定都倒置一下数组是不能接受的,
    还不如直接array_search或者in_array好,
    如果判断值是否存在的操作很多,修改的操作不多,
    那么维护一个value=>key的数组是很有必要的
      

  11.   


    接受大部分意见,代码是有点问题不过,有一点异议是,我这里之所以每次循环倒置key,value,是因为完成外层循环测试N次的目的事实上,每一种查找,都加了外层循环N次,以便排除偶然情况,得到较为客观的结果
      

  12.   

    支持,我一直在用 in_array()
    array_search()这两个方法的。有时会使用 foreach
      

  13.   

      up 这么说反转后isset效率最高?
      

  14.   


    int(5000) int(2) int(100) int(50) 
    0.132363秒 shuffle
    23.241035秒 foreach
    12.559198秒 in_array
    12.540035秒 array_search
    2.459958秒 strpos
    0.393134秒 array_key_exists
    0.396289秒 isset_key