Php 选择散列的第n个元素的最快方法

Php 选择散列的第n个元素的最快方法,php,arrays,Php,Arrays,我有一个大的哈希表(带有字符串索引的数组)并寻找一个函数,该函数可以快速从中选择第一个(理想情况下也是第n个)元素数组移位()和重置()对于我的需要来说太慢了 更新:我也不是在寻找基于引用的解决方案,函数应该接受表达式,如get\u first(some\u func\u returning\u array()) 答案数组_切片法(kudos Gumbo)似乎是赢家。完整的基准测试代码 function bigary($n) { $a = array(); $s = range(

我有一个大的哈希表(带有字符串索引的数组)并寻找一个函数,该函数可以快速从中选择第一个(理想情况下也是第n个)元素<代码>数组移位()和
重置()
对于我的需要来说太慢了

更新:我也不是在寻找基于引用的解决方案,函数应该接受表达式,如
get\u first(some\u func\u returning\u array())

答案数组_切片法(kudos Gumbo)似乎是赢家。完整的基准测试代码

function bigary($n) {
    $a = array();
    $s = range('A', 'Z');
    do {
        shuffle($s);
        $a[substr(implode('', $s), rand(10, 20))] = $n;
    } while(--$n);
    return $a;
}

function timeit($name, $fn) {
    global $results;

    $loops = 1000;
    $size  = 5432;

    static $a;
    if(!$a) $a = bigary($size);

    $t = microtime(1);
    for($i = 0; $i < $loops; $i++)
        $b = $fn($a);
    $results[$name] = microtime(1) - $t;
}

timeit('dummy', function ($a) { 
    // benchmark php function call overhead
});

timeit('array_shift', function ($a) { 
    return array_shift($a); 
});

timeit('reset', function ($a) { 
    return reset($a); 
});

timeit('foreach', function ($a) { 
    foreach($a as $b) return $b;
});

timeit('keys', function ($a) { 
    $b = array_keys($a); 
    return $a[$b[0]];
});

timeit('values', function ($a) { 
    $b = array_values($a); 
    return $b[0];
});

timeit('slice', function ($a) { 
    $b = array_slice($a, 0, 1); 
    return reset($b);
});

asort($results);

foreach($results as $name => $time)
    printf("%20s = %.3f\n", $name, $time);
要获得第一个:

function array_first(array $array) {
     foreach ($array as $value) return $value;
     return false;
}

虽然我还没有测试它的速度,但是您可以尝试使用
array\u values()
将数组转换为数字索引数组

要获取第一个元素,请尝试使用reset(array&$array)重置数组指针。
然后使用current()获取当前值。要获取第n个元素,请使用end()设置指向最后一项的指针。此时,您应该能够使用current()获取第n个项目。

我认为您获取第一个/最后一个元素的速度不会比重置()快

至于N元素,我想不出比这更好的了:

function (&$hashmap, $n) {
    $keys = array_keys($hashmap);
    return $hashmap[$keys[$n]];
}
当然,为了提高性能,可以将其调整为具有预缓存的
$keys
数组(如果hashmap不经常更改的话)。在这种情况下,即使是第0个元素的检索也可能比使用
reset()

来获取仅第n个项目的数组并最终获取它的速度更快:

$nthItem = array_pop(array_slice($arr, $n, 1));

您的基准可能有缺陷,因为:

$fn = function ($a) { 
    return array_shift($a); 
};
timeit('array_shift', $fn);
数组_shift=1.242(5432)

数组_移位=0.026(4433)

而且

$fn = function ($a) { } 
timeit('empty lambda', $fn);
空λ=0.501(0)

话虽如此,另一种可能的解决办法是:

$v = array_values($a);
return $v[ $index ];
示例代码:

$t = microtime(1);
$v = array_values($a); // cached
while($loops--) {
    $b = $v[$loops];
}
数组_值=0.002(5432)


提示:
reset()
end()
还分别返回第一个和最后一个元素的值,因此调用
current()
应该是没有必要的。php手册说reset/end将返回值,而不是引用。但如果他们这么做了,我不明白为什么这对你不好@stereofrogIf
reset()
对您来说实在太慢了,我想知道您是否应该考虑使用另一种语言,特别是编译的而不是解释的语言?我知道这说起来容易做起来难,但老实说,我不确定在保持PHP功能的情况下,您是否能够获得比该函数更快的速度。(尽管我很高兴被证明是错的)你的基准是有缺陷的。缓慢的部分是匿名函数的调用。如果没有,在我的计算机上,
reset
是<0.001,
array\u slice
是<0.001。002@sterofrog,您不需要它,您希望它成为。据了解,这些函数对int索引数组和关联数组的实现似乎有所不同。所以我错的可能性很小(看在你的份上,我也希望如此)。您能用上述解决方案对其进行基准测试吗?很想知道抱歉,以前没有注意到您的基准代码。我的解决方案似乎以1.4s比2.4s的分数输给了
array\u shift
。预缓存密钥解决方案达到了0.7s(这是使用随机访问,即第n个元素),但它只计算了
$keys
一次,所以我认为这不是非常现实的情况。
array\u slice()
,这很好-…但是如果
reset()
对于立体青蛙来说太慢,这将是残酷的[+1表示
array\u值
。如果在一次执行中需要大量
n
值,则只需运行一次,并且始终可以使用
$v[$n]
元素。
$v = array_values($a);
return $v[ $index ];
$t = microtime(1);
$v = array_values($a); // cached
while($loops--) {
    $b = $v[$loops];
}