array_diff()
如何运作?它显然不能如下工作:
function array_diff($arraya, $arrayb)
{
$diffs = array();
foreach ($arraya as $keya => $valuea)
{
$equaltag = 0;
foreach ($arrayb as $valueb)
{
if ($valuea == $valueb)
{
$equaltag =1;
break;
}
}
if ($equaltag == o)
{
$diffs[$keya]=$valuea;
}
}
return $diffs;
} //couldn't be worse than this
有谁知道更好的解决方案?
EDIT @animuson:
function array_diff($arraya, $arrayb)
{
foreach ($arraya as $keya => $valuea)
{
if (in_array($valuea, $arrayb))
{
unset($arraya[$keya]);
}
}
return $arraya;
}
答案 0 :(得分:30)
user187291 建议通过哈希表在PHP中完成它非常棒!从这个幻想中汲取肾上腺素的冲动,我甚至找到了一种方法来加快它的速度(PHP 5.3.1):
function leo_array_diff($a, $b) {
$map = array();
foreach($a as $val) $map[$val] = 1;
foreach($b as $val) unset($map[$val]);
return array_keys($map);
}
基准来自user187291的帖子:
LEO=0.0322 leo_array_diff()
ME =0.1308 my_array_diff()
YOU=4.5051 your_array_diff()
PHP=45.7114 array_diff()
即使每个阵列有100个条目,array_diff()的性能滞后也很明显。
注意:此解决方案意味着第一个数组中的元素是唯一的(或者它们将变为唯一的)。这是散列解决方案的典型特征。
注意:解决方案不保留索引。将原始索引分配给$ map,最后使用array_flip()保存密钥。
function array_diff_pk($a, $b) {
$map = array_flip($a);
foreach($b as $val) unset($map[$val]);
return array_flip($map);
}
PS:我在寻找一些array_diff()paradoxon时发现了这一点:如果在脚本中使用了两次,则array_diff()花费的时间要长三倍才能实现相同的任务。
答案 1 :(得分:23)
更新
see below代码更快/更好。
在php 5.3.4中,array_diff行为要好得多,但仍然比Leo的功能慢10倍。
还值得注意的是,这些函数并不完全等同于array_diff
,因为它们不维护数组键,即my_array_diff(x,y) == array_values(array_diff(x,y))
。
/ UPDATE
更好的解决方案是使用hash maps
function my_array_diff($a, $b) {
$map = $out = array();
foreach($a as $val) $map[$val] = 1;
foreach($b as $val) if(isset($map[$val])) $map[$val] = 0;
foreach($map as $val => $ok) if($ok) $out[] = $val;
return $out;
}
$a = array('A', 'B', 'C', 'D');
$b = array('X', 'C', 'A', 'Y');
print_r(my_array_diff($a, $b)); // B, D
基准
function your_array_diff($arraya, $arrayb)
{
foreach ($arraya as $keya => $valuea)
{
if (in_array($valuea, $arrayb))
{
unset($arraya[$keya]);
}
}
return $arraya;
}
$a = range(1, 10000);
$b = range(5000, 15000);
shuffle($a);
shuffle($b);
$ts = microtime(true);
my_array_diff($a, $b);
printf("ME =%.4f\n", microtime(true) - $ts);
$ts = microtime(true);
your_array_diff($a, $b);
printf("YOU=%.4f\n", microtime(true) - $ts);
结果
ME =0.0137
YOU=3.6282
有什么问题吗? ;)
而且,只是为了好玩,
$ts = microtime(true);
array_diff($a, $b);
printf("PHP=%.4f\n", microtime(true) - $ts);
结果
ME =0.0140
YOU=3.6706
PHP=19.5980
这太不可思议了!
答案 2 :(得分:7)
知道它是如何工作的最佳解决方案来看看它的源代码;-)
(嗯,这是开源的权力之一 - 如果你看到一些可能的优化,你可以提交一个补丁;-))
对于array_diff,它应该在ext/standard
- 这意味着,对于PHP 5.3,它应该在那里:branches/PHP_5_3/ext/standard
然后,array.c
文件看起来像一个看似合理的目标; php_array_diff
函数第3381行似乎与array_diff
对应。
(祝你好运通过代码:它很长......)
答案 3 :(得分:2)
似乎你可以通过使用另一个数组而不是取消设置来加快速度。但是,这会占用更多内存,这可能是一个问题,这取决于用例(我还没有测试过内存分配的实际差异)。
<?php
function my_array_diff($a, $b) {
$map = $out = array();
foreach($a as $val) $map[$val] = 1;
foreach($b as $val) if(isset($map[$val])) $map[$val] = 0;
foreach($map as $val => $ok) if($ok) $out[] = $val;
return $out;
}
function leo_array_diff($a, $b) {
$map = $out = array();
foreach($a as $val) $map[$val] = 1;
foreach($b as $val) unset($map[$val]);
return array_keys($map);
}
function flip_array_diff_key($b, $a) {
$at = array_flip($a);
$bt = array_flip($b);
$d = array_diff_key($bt, $at);
return array_keys($d);
}
function flip_isset_diff($b, $a) {
$at = array_flip($a);
$d = array();
foreach ($b as $i)
if (!isset($at[$i]))
$d[] = $i;
return $d;
}
function large_array_diff($b, $a) {
$at = array();
foreach ($a as $i)
$at[$i] = 1;
$d = array();
foreach ($b as $i)
if (!isset($at[$i]))
$d[] = $i;
return $d;
}
$functions = array("flip_array_diff_key", "flip_isset_diff", "large_array_diff", "leo_array_diff", "my_array_diff", "array_diff");
#$functions = array_reverse($functions);
$l = range(1, 1000000);
$l2 = range(1, 1000000, 2);
foreach ($functions as $function) {
$ts = microtime(true);
for ($i = 0; $i < 10; $i++) {
$f = $function($l, $l2);
}
$te = microtime(true);
$timing[$function] = $te - $ts;
}
asort($timing);
print_r($timing);
我的时间是(PHP 5.3.27-1~dotdeb.0):
[flip_isset_diff] => 3.7415699958801
[flip_array_diff_key] => 4.2989008426666
[large_array_diff] => 4.7882599830627
[flip_flip_isset_diff] => 5.0816700458527
[leo_array_diff] => 11.086831092834
[my_array_diff] => 14.563184976578
[array_diff] => 99.379411935806
找到了三个新功能
答案 4 :(得分:1)
由于这已经提出(参见@ BurninLeo的回答),这样的事情怎么样?
function binary_array_diff($a, $b) {
$result = $a;
asort($a);
asort($b);
list($bKey, $bVal) = each($b);
foreach ( $a as $aKey => $aVal ) {
while ( $aVal > $bVal ) {
list($bKey, $bVal) = each($b);
}
if ( $aVal === $bVal ) {
unset($result[$aKey]);
}
}
return $result;
}
在进行一些测试后,结果似乎是可以接受的:
$a = range(1, 10000);
$b = range(5000, 15000);
shuffle($a);
shuffle($b);
$ts = microtime(true);
for ( $n = 0; $n < 10; ++$n ) {
array_diff($a, $b);
}
printf("PHP => %.4f\n", microtime(true) - $ts);
$ts = microtime(true);
for ( $n = 0; $n < 10; ++$n ) {
binary_array_diff($a, $b);
}
printf("binary => %.4f\n", microtime(true) - $ts);
$binaryResult = binary_array_diff($a, $b);
$phpResult = array_diff($a, $b);
if ( $binaryResult == $phpResult && array_keys($binaryResult) == array_keys($phpResult) ) {
echo "returned arrays are the same\n";
}
输出:
PHP => 1.3018
binary => 1.3601
returned arrays are the same
当然,PHP代码的性能不如C代码,因此毫无疑问PHP代码会慢一些。
答案 5 :(得分:-2)
来自PHP:“返回一个数组,其中包含array1中任何其他数组中不存在的所有条目。”
因此,您只需针对所有 arrayN 检查 array1 , array1 中任何未出现在任何这些数组中的值都将是以新数组返回。
您甚至不需要遍历所有 array1 的值。仅针对所有其他数组,循环遍历其值并检查每个值是否为in_array($array1, $value)
。