在(可能是)关联数组中获取第一个键?

819

如何确定可能关联数组中的第一个键?我的第一个想法是遍历整个数组,然后立即中断,代码如下:

foreach ($an_array as $key => $val) break;

因此,让$key 包含第一个键,但这似乎效率低下。有没有更好的解决方案?


4
为什么for循环效率低? - Emilio Gort
2
与所有答案相比,foreach仍然是最快的[FIDDLE, PHP 5.3](http://phpfiddle.org/lite/code/916y-x8m8),我在本地主机上对PHP 5.5进行的测试表明,foreach稍微更胜一筹。 - Danijel
3
@Danijel,“foreach”的语义不正确。 - Pacerier
2
@AlexS,each($arr)['key']each($arr)[0] 都可以。 - Pacerier
1
@Danijel 不再是这样了... 关键字: 0.0107, foreach: 0.0217 - SeanJA
显示剩余2条评论
25个回答

1426

2019年更新

PHP 7.3开始,有一个新的内置函数叫做array_key_first(),它将从给定的数组中检索第一个键而不重置内部指针。查看文档了解更多信息。


你可以使用resetkey

reset($array);
$first_key = key($array);

这与您最初的代码基本相同,但开销要小一些,并且更容易理解正在发生的事情。

请记得调用reset,否则您可能会得到数组中的任何键。您还可以使用end而不是reset来获取最后一个键。

如果您想要获取第一个值的键,实际上reset返回它:

$first_value = reset($array);

不过有一个特殊情况需要注意(所以先检查数组的长度):

$arr1 = array(false);
$arr2 = array();
var_dump(reset($arr1) === reset($arr2)); // bool(true)

150
顺便提一下,reset()也恰好会返回任何数组的第一个元素(值,而不是键),这也很方便。 - devios1
6
文档中有一条关于reset()的注释,它说“不要使用reset()来获取关联数组的第一个值。对于真正的数组来说它很好用,但是在迭代器对象上会出现意想不到的结果。http://bugs.php.net/bug.php?id=38478”。这是否仍然正确?我感到困惑。 - Dmitry Pashkevich
15
不用担心那个评论。他们说的不是“array”对象,而是自定义对象(不是真正的数组)。我想他们混淆了数据结构的区别,但基本上,“reset”返回第一个“键”的值,在“bug”报告中给出的示例中对于对象来说会是“$prop”,但对于数组来说是第一个键。所以不用担心,只要你使用真正的数组(使用“array(…)”创建),就不会有问题。 - Blixt
2
应该提到,end()和reset()有副作用。然而,世界上大多数代码并不依赖于内部指针的位置,因此这通常不是问题。 - donquixote
1
@Blixt,是的,但我们不应该防范这种情况。我们必须理解并信任我们包含在系统中的库。它们被认为不会搞砸像调用exit;或忘记关闭它们打开的东西等等。 - Pacerier
显示剩余8条评论

86

array_keys 返回一个包含所有键名的数组。获取第一个条目。或者,您可以在数组上调用reset,然后使用key。后一种方法可能略微快一些(虽然我没有测试过),但它会重置内部指针。


54
这只是给未来读者的一条(迟到的)说明:后一种方法不仅仅是“稍微”快一点。在遍历整个数组、将每个键存储到另一个新创建的数组中并请求数组的第一个键作为字符串之间有很大的区别。 - Blixt
3
为什么在问题中效率低下的foreach与所有这些答案相比要差? - Emilio Gort
6
@EmilioGort 好问题。我认为使用foreach + breakreset + key 并没有性能上的区别。但是前者看起来相当奇怪,所以基于风格方面考虑,我更喜欢使用后者。 - troelskn
据我所知,foreach()在内部复制数组。因此我们可以认为它会更慢一些。(如果有人能够确认一下就好了) - donquixote
4
我不确定,但是假设这是一个常规数组(而不是实现某种迭代器接口的对象),我相当确定 foreach 不会为它创建内部副本,而只是迭代一个指针,类似于使用更低级别的 nextcurrent 等。 - troelskn
显示剩余3条评论

55

有趣的是,使用foreach循环实际上是做这件事情最有效的方法。

既然原帖子特别询问了效率问题,应该指出当前所有答案实际上都比foreach要慢得多。

我在php 5.4上进行了基准测试,发现重置/键指针方法(被采纳的答案)大约比foreach慢7倍。其他操作整个数组的方法(array_keys,array_flip)显然比这更慢,并且在处理大型数组时会变得更糟

Foreach根本不低效,请放心使用它!

编辑于2015-03-03:

已请求基准测试脚本,我没有原始文件,但代替做了一些新的测试。这次我发现foreach只比重置/键快两倍左右。我使用了一个100键数组,并运行了每种方法一百万次以获得一些明显的差异,以下是简单基准测试的代码:

$array = [];
for($i=0; $i < 100; $i++)
    $array["key$i"] = $i;

for($i=0, $start = microtime(true); $i < 1000000; $i++) {
    foreach ($array as $firstKey => $firstValue) {
        break;
    }
}
echo "foreach to get first key and value: " . (microtime(true) - $start) . " seconds <br />";

for($i=0, $start = microtime(true); $i < 1000000; $i++) {
    $firstValue = reset($array);
    $firstKey = key($array);
}
echo "reset+key to get first key and value: " . (microtime(true) - $start) . " seconds <br />";

for($i=0, $start = microtime(true); $i < 1000000; $i++) {
    reset($array);
    $firstKey = key($array);
}
echo "reset+key to get first key: " . (microtime(true) - $start) . " seconds <br />";


for($i=0, $start = microtime(true); $i < 1000000; $i++) {
    $firstKey = array_keys($array)[0];
}
echo "array_keys to get first key: " . (microtime(true) - $start) . " seconds <br />";

在我的 PHP 5.5 上,这个输出为:

foreach to get first key and value: 0.15501809120178 seconds 
reset+key to get first key and value: 0.29375791549683 seconds 
reset+key to get first key: 0.26421809196472 seconds 
array_keys to get first key: 10.059751987457 seconds

重置+键 http://3v4l.org/b4DrN/perf#tabs
遍历 http://3v4l.org/gRoGD/perf#tabs


3
你是否有基准测试的数据,比如你是如何进行测试的等等。不管怎样,感谢你进行测试! - flu
我想指出一个事实,整个测试中都使用了同一个数组。我认为这一事实显著地影响了foreach方法的运行。正如@donquixote在先前的某个回复中提到的,foreach内部会复制该数组。我可以想象,在运行基准测试时会重复使用此副本,因为避免数组复制仅在此测试中增强了性能。 - Jarda
2
@Jarda 自 PHP7 开始,foreach 循环不会复制数组,除非你在 foreach 循环内直接修改它。在 PHP5 中,在某些情况下(当其 refcount > 1 时)可能会复制数组结构,你实际上是正确的,这可能会对性能产生重大影响。幸运的是,在 PHP7 上,这个问题已经得到解决,所以不用担心了。这里有一个很好的阅读材料,介绍了现在和过去 foreach 的工作原理。 - Webmut
2
截至PHP7.2,使用上述基准测试,foreach仍然是最快的。 - But those new buttons though..

39

key($an_array)将会给你第一个键。

根据Blixt的修改:在调用key($an_array)之前,应该调用reset($array);以将指针重置为数组的开头。


7
请记住,数组的指针可能不在第一个元素处,请查看我的答案。 - Blixt
我认为这个答案会对我的情况有所帮助,因为我首先确保数组只有一个元素。谢谢。 - groovenectar

37

你可以尝试一下

array_keys($data)[0]

在我看来,这是正确的答案。 - Sérgio

30

从2018年开始

自PHP 7.3起,有一个array_key_first()函数可以完全实现这一功能:

$array = ['foo' => 'lorem', 'bar' => 'ipsum'];
$firstKey = array_key_first($array); // 'foo'

文档可在此处获取。


21
如果效率对您不是那么重要,您可以在 PHP 5.4(及更高版本)中使用 array_keys($yourArray)[0]示例:
# 1
$arr = ["my" => "test", "is" => "best"];    
echo array_keys($arr)[0] . "\r\n"; // prints "my"


# 2
$arr = ["test", "best"];
echo array_keys($arr)[0] . "\r\n"; // prints "0"

# 3
$arr = [1 => "test", 2 => "best"];
echo array_keys($arr)[0] . "\r\n"; // prints "1"

解决方案的优势:

list($firstKey) = array_keys($yourArray);

你可以将array_keys($arr)[0]作为函数参数传递(例如:doSomething(array_keys($arr)[0], $otherParameter))。

希望对你有所帮助


3
array_keys($arr)[0] 语法是否有效? - trante
5
这段话的意思是:这是在PHP 5.4中引入的一个特性,叫做"数组解引用"。可以参考这个链接了解更多信息:http://schlueters.de/blog/archives/138-Features-in-PHP-trunk-Array-dereferencing.html - MartyIX
@trante,除了PHP < 5.4之外,它在太阳下的每种语言中都是有效的。 - Pacerier

21
list($firstKey) = array_keys($yourArray);

3
这可能不是最有效的做法。 - Yada
3
@Yada,是的,但这可能只在少数情况下会被注意到;在大多数情况下,可读性和可维护性更加重要;我也更喜欢不改变原始对象/数组的解决方案:例如reset($ar); $key = key($ar);并不总是一个好主意,我宁愿选择MartyIX的解决方案,它比我的更简洁,例如:array_keys($ar)[0]; - Sergiy Sokolenko

15

请查看以下内容:

$yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$keys   =   array_keys($yourArray);
echo "Key = ".$keys[0];

可运行示例:


12
$myArray = array(
    2 => '3th element',
    4 => 'first element',
    1 => 'second element',
    3 => '4th element'
);
echo min(array_keys($myArray)); // return 1

1
@jurgemaister max() 不会返回关联数组的第一个键。max() 返回列表或数组项的最大值。 - Hamidreza
5
并非楼主的要求,但在某些情况下非常有用。 - d.raev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接