确定可能关联数组中的第一个键的最佳方法是什么?我的第一个想法是在数组前面,然后立即将其破坏,如下所示:
1
| foreach ($an_array as $key => $val) break; |
因此,$key包含第一个key,但这看起来效率很低。有人有更好的解决方案吗?
- 为什么前臂效率低下?
- 与所有的答案相比,foreach仍然是最快的小提琴,php 5.3,我在php5.5上的本地主机测试显示,两者之间的差异有点偏向于foreach。
- @但尼尔,埃多克斯1〔0〕在语义上是错误的。
- @亚历克斯,要么是埃多克斯1〔1〕要么是埃多克斯1〔2〕会起作用。
- @丹尼尔不再……密钥:0.0107,foreach:0.0217。
- 注意,如果$an_数组是空的,如果幸运的话,这个解决方案会给出"未定义的变量",或者如果不是,它会根据$key的现有值给出未定义的结果。
- 在php 7中,foreach仍然是最有效的方法,但正如@pacerier所说,它在语义上是错误的。基准:php -r '$n="
";$m="microtime";$t=function($s,$e){$s=explode("",$s);$e=explode("",$e);return$e[1]-$s[1]+$e[0]-$s[0];};$a=[]; for($i=0;$i<100;++$i){$a["k".$i]=$i;}echo implode(",",$a),$n;reset($a);echo"key():";$s=$m();for($i=0;$i<1e6;++$i){$k=key($a);}echo$k,$n,$t($s,$m()),$n; reset($a);echo"foreach:";$s=$m();for($i=0;$i<1e6;++$i){foreach($a as$k=>$v){break;}}echo$k,$n,$t($s,$m()),$n;'。
2019更新
从php 7.3开始,有一个名为array_key_first()的新内置函数,它可以从给定数组中检索第一个键,而不必重置内部指针。查看文档了解更多信息。
您可以使用reset和key:
1 2
| reset($array);
$first_key = key($array); |
它本质上与您的初始代码相同,但是开销稍微少一点,而且更明显的是发生了什么。
只需记住调用reset,否则您可能会得到数组中的任何键。您也可以使用end而不是reset来获取最后一个密钥。
如果您希望键获得第一个值,那么reset实际上会返回它:
1
| $first_value = reset($array); |
但有一个特殊情况需要注意(因此,请首先检查数组的长度):
- 作为补充说明,reset()还碰巧返回任何数组的第一个元素(值,而不是键),这也很方便。
- 在对reset()的文档中有一条注释,说Don't use reset()`获取关联数组的第一个值。它适用于真正的数组,但在迭代器对象上意外工作。bugs.php.net/bug.php?id=38478`这是真的吗?我很困惑
- @德米特里帕斯凯维奇:别担心这个评论。他们说的不是array对象,而是自定义对象(不是实际的数组)。我猜他们混淆了数据结构的区别,但基本上,reset返回第一个"key"的值,在"bug"报告中给出的示例中,对象的值将是$prop,而对于数组,则是第一个key。所以不用担心,只要使用真实数组(使用array(…)创建),就不会有问题。
- 为什么与所有这些答案相比,OP在问题中的效率低下?
- 应该提到,end()和reset()有副作用。然而,世界上大多数代码并不依赖于内部指针在任何地方,所以这通常不是问题。
- 抱歉,如果在作为参数传递给函数的数组上的函数内部调用key(),应该在前面使用reset(),还是可以直接安全地使用key()?
- @用户3019105每个数组只有一个内部指针,这意味着如果函数之外的任何代码(通过调用next、reset、end或通过数组循环)更改了它,那么调用key时就不会得到预期值。所以是的,在使用key之前,一定要先打电话给reset,以确保你得到你想要的。
- @Blixt,好吧,另一种方法是确保代码在完成后能够自我清理。因此,在这种情况下,我们会在调用key之后调用reset,如果在整个代码库中强制执行,它会很好地工作。
- @Pacerier是真的,我也不喜欢防御性编程,但在这种情况下,我认为通过添加reset语句,代码可以变得更健壮,并且不太依赖代码库的其余部分。风险在于,其他人使用不知道的第三方库调用next或数组上的某个内容,这将打破该数组已在其他地方重置的假设。
- @是的,但我们不应该对此有所防范。我们必须理解并信任我们系统中包含的库。他们被假定不会把事情搞砸,比如打电话给exit;,或者忘记关闭他们打开的东西,什么都不关。
- 当使用"array-like"对象(例如,ArrayObject)而不是php本机数组时,end似乎会在hhvm中导致错误。
- reset()是否也改变了源数组?
- @jocull reset($a)改变数组$a的内部键指针,但不改变值或键本身。
array_keys返回一个键数组。进入第一个入口。或者,您可以在数组上调用reset,然后调用key。后一种方法可能稍快一些(尽管我没有测试它),但它有重置内部指针的副作用。
- 对于未来的读者来说,这只是一个(后期的)注释:后一种方法不仅仅是"稍微"快一点。迭代整个数组、将每个键存储在另一个新创建的数组中以及将数组的第一个键作为字符串请求之间有很大的区别。
- 为什么与所有这些答案相比,OP在问题中的效率低下?
- @Emiliogort好问题。我认为实际上,foreach+break+reset+key的性能没有任何差别。但是前者看起来很奇怪,所以对于风格问题,我更喜欢后者。
- @emiliogort:afaik,foreach()在内部复制数组。所以我们可以假设它变慢了。(如果有人能证实这一点,那就太好了)
- @Donquixote我不确定,但假设它是一个正则数组(而不是实现某种类型或迭代器接口的对象),我相当确定foreach不会为它创建内部副本,而是迭代一个指针,类似于使用更低级的next和current等。
- @特罗尔斯克今天学到了一些东西!nikic.github.io/2011/11/11/&hellip;。我对"引用的"示例有点困惑,但我认为这与延迟复制数组参数有关。不过,我们仍然需要一个基准来比较foreach()和reset()+key()。
- 隐马尔可夫模型。。这就是说,array_keys()可能是最昂贵的部分!除非php还有另一种"欺骗"的方法,让它变得便宜。
- foreach的优点是它现在是一个更常见的用例,因此与key相比,PHP引擎更可能优化它。
有趣的是,foreach循环实际上是最有效的方法。
由于OP特别询问效率,应该指出,所有当前的答案实际上都比foreach效率低得多。
我用php 5.4做了一个基准测试,reset/key指针方法(接受的答案)看起来比foreach慢7倍。其他处理整个数组的方法(数组键、数组翻转)明显比这还要慢,并且在处理大型数组时会变得更糟。
foreach一点效率都不低,请随意使用它!
编辑2015-03-03:
已经请求了基准脚本,我没有原始脚本,而是进行了一些新的测试。这次我发现前臂的速度只有重置/键的两倍。我使用了一个100键数组,并对每个方法运行了一百万次,以获得一些显著的差异,下面是简单基准测试的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| $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上,这个输出:
10
重置+键http://3v4l.org/b4drn/perf_tabsforeach http://3v4l.org/grogd/perf标签
- 你有什么基准吗?就像你如何测试等等。不管怎样,谢谢你运行它们!
- 我想指出的是,在整个测试中使用了相同的数组。我认为这一事实显著影响了前臂入路。正如上面对某些响应的注释中提到的@donquixote,foreach在内部复制数组。我可以想象这个副本在运行基准测试时被重用,因为避免数组复制只提高了这个测试中的性能。
- @Jarda从php7开始,foreach从不复制数组,除非您直接在foreach循环中修改它。在php5上,数组结构可能在某些情况下被复制(当其refcount>1时),而实际上您是对的,它可能会对那里产生重大影响。幸运的是,在解决了这个问题的PHP7上没有什么可担心的。这是一本关于前臂现在如何在引擎盖下工作以及过去如何工作的好书。
- 从PHP7.2开始,使用上述基准,foreach仍然是最快的。
key($an_array)会给你第一把钥匙
编辑每一个文本:您应该在key($an_array)之前调用reset($array);,将指针重置到数组的开头。
- 记住数组的指针可能不在第一个元素上,请看我的答案。
- 我认为这个答案有助于我的情况下不重置,因为我首先要确保数组只有一个元素。谢谢
你可以试试
- 这可能不是最有效的。
- @Yada,是的,但这在少数情况下可能会很明显;在大多数情况下,可读性和可维护性更为重要;我也更喜欢不改变原始对象/数组的解决方案:例如重置($ar);$key=key($ar);--这并不总是好主意,我宁愿选择比我的解决方案更简洁的martyix,例如:array_键($ar)[0];
如果效率对您来说不是那么重要,那么可以在php 5.4(及更高版本)中使用array_keys($yourArray)[0]。
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| # 1
$arr = ["my" =>"test","is" =>"best"];
echo array_keys($arr)[0] ."
"; // prints"my"
# 2
$arr = ["test","best"];
echo array_keys($arr)[0] ."
"; // prints"0"
# 3
$arr = [1 =>"test", 2 =>"best"];
echo array_keys($arr)[0] ."
"; // prints"1" |
相对于解决方案的优势:
可以将array_keys($arr)[0]作为函数参数(即doSomething(array_keys($arr)[0], $otherParameter))传递。
高温高压
- array_keys($arr)[0]语法有效吗?
- 它在php 5.4中。它叫array dereferencing。如:schlueters.de/blog/archives/&hellip;
- @Trante,除了php<5.4之外,它在Sun下的所有语言中都有效。
2018 +从php 7.3开始,有一个array_key_first()函数可以实现这一点:
1 2
| $array = ['foo' => 'lorem', 'bar' => 'ipsum'];
$firstKey = array_key_first($array); // 'foo' |
此处提供文档。???
1 2 3 4 5 6 7
| $myArray = array(
2 => '3th element',
4 => 'first element',
1 => 'second element',
3 => '4th element'
);
echo min(array_keys($myArray)); // return 1 |
- 这完全解决了我的问题,只使用了max()。
- @jurgemaister max()不返回assoc数组的第一个键。max返回列表或数组项的最大值
- 不是OP请求,但在某些情况下非常有用。
- 它不适用于字符串键。
请查找以下内容:
1 2 3
| $yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$keys = array_keys($yourArray);
echo"Key =".$keys[0]; |
工作示例:
这也可能是一个解决方案。
1 2 3
| $yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$first_key = current(array_flip($yourArray));
echo $first_key; |
我已经测试过了,它能工作。
工作代码:
- array_flip():只能翻转字符串和整数值!
为了增强webmut的解决方案,我添加了以下解决方案:
php 7.1上我的输出是:
1 2 3 4 5
| foreach to get first key and value : 0.048566102981567 seconds
reset+key to get first key and value : 0.11727809906006 seconds
reset+key to get first key: 0.11707186698914 seconds
array_keys to get first key: 0.53917098045349 seconds
array_slice to get first key: 0.2494580745697 seconds |
如果对大小为10000的数组执行此操作,则结果将变为
1 2 3 4
| foreach to get first key and value : 0.048488140106201 seconds
reset+key to get first key and value : 0.12659382820129 seconds
reset+key to get first key: 0.12248802185059 seconds
array_slice to get first key: 0.25442600250244 seconds |
数组键方法在30秒时超时(只有1000个元素,其余元素的计时大致相同,但数组键方法有7.5秒左右)。
对我来说最好的方法是
array_keys从初始数组中获取键数组,然后array_shift从它的第一个元素值中削减。您需要使用php 5.4+。
1 2 3 4
| $arr = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
list($first_key) = each($arr);
print $first_key;
// key1 |
PHP73:
1 2 3 4
| $array = ['a' => '..', 'b' => '..'];
array_key_first($array); // 'a'
array_key_last($array); // 'b'; |
http://php.net/manual/en/function.array-key-first.php
- 包括一个解释真的有助于提高你的文章的质量。请记住,您将来会回答读者的问题,而这些人可能不知道您的代码建议的原因。
这是我发现的最简单的方法。快速,只有两行代码:-d
1 2
| $keys = array_keys($array);
echo $array[$keys[0]]; |
一个班轮:
1 2 3 4
| $array = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
echo key( array_slice( $array, 0, 1, true ) );
# echos 'key1' |
今天我必须搜索一个post请求返回的数组的第一个键。(并记下表格ID等的编号)
我发现了:返回PHP中关联数组的第一个键
http://php.net/key/键
我已经做到了,而且很有效。
1 2 3 4 5 6 7
| $data = $request->request->all();
dump ($data);
while ($test = current($data)) {
dump ($test);
echo key($data).'<br />';die();
break;
} |
也许它会比其他人长15分钟。CYA。
你可以玩你的阵列
1 2 3 4 5 6 7
| $daysArray = array('Monday', 'Tuesday', 'Sunday');
$day = current($transport); // $day = 'Monday';
$day = next($transport); // $day = 'Tuesday';
$day = current($transport); // $day = 'Tuesday';
$day = prev($transport); // $day = 'Monday';
$day = end($transport); // $day = 'Sunday';
$day = current($transport); // $day = 'Sunday'; |
要获得数组的第一个元素,可以使用current,对于最后一个元素,可以使用end。
编辑
为了不获得更多的选票,您可以使用array_keys将密钥转换为值,并使用如上所示。