php array_intersect() 效率

Posted

技术标签:

【中文标题】php array_intersect() 效率【英文标题】:php array_intersect() efficiency 【发布时间】:2011-06-13 10:27:13 【问题描述】:

考虑下面的脚本。只有三个值的两个数组。当我使用 array_intersect() 比较这两个数组时。结果很快。

    <?php
$arrayOne = array('3', '4', '5');
$arrayTwo = array('4', '5', '6');

$intersect = array_intersect($arrayOne, $arrayTwo);

print_r($intersect );

?>

我的问题是array_intersect() 的效率是多少。我们是否比较两个数组,每个数组都有 1000 个值。会产生更好的结果.....r 我们需要使用一些散列函数来处理快速找到共同值这将是有效的???..我需要你的建议...

我正在做一个应用程序。如果有人来并使用 facebook login.then 应用程序将获取他的朋友列表,并查找之前在我的应用程序中评论过的任何朋友并将其显示给他。大约一个朋友在 facebook 上可能有 200 到 300 个朋友,而 db 有超过 1000 条记录。我需要有效地找到那个我该怎么做.......

【问题讨论】:

@learnfromothers :您是否在具有 1000 多个值的数组上尝试过相同的操作? 为什么不自己找找呢?做一个基准。一般来说,它是否有效并不重要,除非您分析了您的应用程序并发现对 array_intersect 的调用显着减慢了您的应用程序。重要程度取决于您的要求。 @Coding Freak 不,我没有尝试过。我正在做一个应用程序。如果一个人来并使用 facebook login.then 登录。然后该应用程序将获取他的朋友列表,并查找之前在我的应用程序中是否有任何朋友评论并将其显示给他。大约一个朋友在 facebook 上可能有 200 到 300 个朋友,而 db 有超过 1000 条记录。我需要有效地找到那个我该怎么做....... @Gordan 对于这个任何解决方案.....我正在做一个应用程序。如果有人来并使用 facebook login.then 应用程序将获取他的朋友列表并查找是否有评论的朋友之前在我的应用程序中显示给他。大约一个朋友在 facebook 上可能有 200 到 300 个朋友,而 db 有超过 1000 条记录。我需要有效地找到那个我该怎么做....... 但是你怎么能确定你会遇到只有 200 到 300 个朋友的人呢?我在 facebook 上看到拥有超过 5000 个朋友的个人资料。 【参考方案1】:

可以通过在第二个数组中构造一组搜索值来实现交集,并且在一组中查找可以非常快,以至于平均花费基本上恒定的时间。所以整个算法的运行时间可以在O(n)

或者,可以对第二个数组进行排序(在O(n log n) 中)。由于在排序数组中查找在O(log n) 中有一个运行时,因此整个算法应该在O(n log n) 中有一个运行时。

根据我刚刚运行的(简短的、不科学的)测试,php 的array_intersect 似乎是这种情况:

Here's the code我曾经测试过。如您所见,对于小至 1000 的输入大小,您无需担心。

【讨论】:

@phinag 是对的......对于这个任何解决方案......我正在做一个应用程序。如果一个人来并使用 facebook login.then 应用程序将获取他的朋友列表并查找是否有任何朋友之前在我的应用中发表过评论并将其展示给他。大约一个朋友在 facebook 上可能有 200 到 300 个朋友,而 db 有超过 1000 条记录。我需要有效地找到它我该怎么做。 @learnfromothers array_intersect 不会是少于一千个元素的性能问题。 谢谢。为了你的效果。非常满意您的回答....再次感谢.... ... @phihag 如果你还记得的话,你用来获取该图表的工具是什么? @vicch 抱歉,我不记得了,而且我找不到生成图表的代码(另一方面,获取 data 的代码, 链接到答案中)。这可能是 gnuplot 或 matplotlib。但我不能排除 LibreOffice 甚至是手工编码的脚本。【参考方案2】:

array_intersect 在并行比较它们的值之前对数组进行排序(参见source file array.czend_qsort 的使用)。对于每个数组,仅此一项就需要 O(n·log n)。那么实际的交叉点只需要线性时间。

根据数组中的值,您可以在不进行排序的情况下在线性时间内实现此交集,例如:

$index = array_flip($arrayOne);
foreach ($arrayTwo as $value) 
    if (isset($index[$value])) unset($index[$value]);

foreach ($index as $value => $key) 
    unset($arrayOne[$key]);

var_dump($arrayOne);

【讨论】:

【参考方案3】:

我找到的最快的解决方案:

function arrayIntersect($arrayOne, $arrayTwo) 
        $index = array_flip($arrayOne);
        $second = array_flip($arrayTwo);

        $x = array_intersect_key($index, $second);

        return array_flip($x);

我所做的测试如下所示:

function intersect($arrayOne, $arrayTwo)

    $index = array_flip($arrayOne);
    foreach ($arrayTwo as $value) 
        if (isset($index[$value])) unset($index[$value]);
    
    foreach ($index as $value => $key) 
        unset($arrayOne[$key]);
    

    return $arrayOne;


function intersect2($arrayOne, $arrayTwo)

    $index = array_flip($arrayOne);
    $second = array_flip($arrayTwo);

    $x = array_intersect_key($index, $second);

    return array_flip($x);



for($i =0; $i < 1000000; $i++) 
    $one[] = rand(0,1000000);
    $two[] = rand(0,100000);
    $two[] = rand(0,10000);


$one = array_unique($one);
$two = array_unique($two);

$time_start = microtime(true);
$res = intersect($one, $two);
$time = microtime(true) - $time_start;

echo "Sort time $time seconds 'intersect' \n";


$time_start = microtime(true);
$res2 = array_intersect($one, $two);
$time = microtime(true) - $time_start;

echo "Sort time $time seconds 'array_intersect' \n";


$time_start = microtime(true);
$res3 = intersect2($one, $two);
$time = microtime(true) - $time_start;

echo "Sort time $time seconds 'intersect2' \n";

php 5.6 的结果:

Sort time 0.77021193504333 seconds 'intersect' 
Sort time 6.9765028953552 seconds 'array_intersect' 
Sort time 0.4631941318512 seconds 'intersect2'

【讨论】:

点评来源: 您好,请不要只回答源代码。尝试对您的解决方案如何工作提供一个很好的描述。请参阅:How do I write a good answer?。谢谢【参考方案4】:

根据您上面所说的,我建议您实现缓存机制。这样你就可以加载数据库并加速你的应用程序。我还建议您随着数据量的增加来分析 array_intersect 的速度,以了解性能如何扩展。您可以通过简单地将调用包装在系统时间的调用中并计算差异来做到这一点。但我建议您使用真正的分析器来获取良好的数据。

【讨论】:

@learnfromothers:分析器是一种可以帮助您测量应用程序性能的应用程序。以 Xdebug 为例:xdebug.org/docs/profiler 或者如果您使用 Zend Studio,他们有一个内置的:files.zend.com/help/Beta/Zend_Studio_8_0/… @inquam 谢谢。我可以使用一些哈希函数将值存储在 db 中,以便可以限制搜索。这是正确的方法吗??? @learnfromothers:访问数据的最佳方式取决于多种因素。数据的布局、读取和写入的频率等。但是使用分析器,您可以快速了解不同的方法和特定更改如何影响您的性能。 @inquam 再次感谢....但是您是否知道当今以及在 facebook 等主要网站中用于有效存储和检索数据的任何最佳方法.... @laernfromothers:我知道例如 Facebook 严重依赖数据缓存。我认为他们使用的是 memcache 的修改版本。与一直从数据库获取数据相比,这将数据存储在内存中并且速度非常快。另外,我认为他们预先计算关键信息位,这样您就不必每次都这样做。说出你的朋友名单。您可以编译一次并将其存储在缓存中。然后,您可以在每次需要时从那里检索它。只有在您添加或删除朋友后,才需要重建。【参考方案5】:

我实现了这个比较array_intersect和array_intersect_key的简单代码,

$array = array();
    for( $i=0; $i<130000; $i++)
        $array[$i] = $i;
    for( $i=200000; $i<230000; $i++)
        $array[$i] = $i;
    for( $i=300000; $i<340000; $i++)
        $array[$i] = $i;

    $array2 = array();
    for( $i=100000; $i<110000; $i++)
        $array2[$i] = $i;
    for( $i=90000; $i<100000; $i++)
        $array2[$i] = $i;
    for( $i=110000; $i<290000; $i++)
        $array2[$i] = $i;

    echo 'Intersect to arrays -> array1[' . count($array) . '] : array2[' . count($array2) . '] ' . '<br>';
    echo date('Y-m-d H:i:s') . '<br>';
    $time = time();
    $array_r2 = array_intersect_key($array,$array2);
    echo 'Intercept key: ' . (time()-$time) . ' segs<br>';
    $time = time();
    $array_r = array_intersect($array,$array2);
    echo 'Intercept: ' . (time()-$time) . ' segs<br>';

结果……

Intersect to arrays -> array1[200000] : array2[200000] 
2014-10-30 08:52:52
Intercept key: 0 segs
Intercept: 4 segs

在这个array_intersect和array_intersect_key的效率比较中,我们可以看到用keys的拦截要快得多。

【讨论】:

以上是关于php array_intersect() 效率的主要内容,如果未能解决你的问题,请参考以下文章

php动态array_intersect

php中的array_intersect()具有特殊用途

PHP:正则表达式替代 array_intersect

PHP使用array_intersect()函数求数组交集

Php array_intersect输出[重复]

php函数array_intersect中的参数问题