Получить первый ключ в (возможно) ассоциативном массиве?

757

Какой лучший способ определить первый ключ в возможно ассоциативном массиве? Сначала я подумал, что нужно просто просмотреть массив, а затем сразу же разбить его, вот так:

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

Таким образом, наличие ключа $ содержит первый ключ, но это кажется неэффективным. У кого-нибудь есть лучшее решение?

Алекс С
источник
4
Почему неэффективный foreach?
Эмилио Горт
2
По сравнению со всеми ответами, foreach по-прежнему самая быстрая FIDDLE, PHP 5.3 , мой тест localhost на PHP 5.5 показывает, что разница немного в пользу foreach.
Даниэль
3
@Danijel, foreachсемантически неверен.
Pacerier
2
@AlexS, Либо each($arr)['key']или each($arr)[0]будет работать.
Pacerier
1
@Danijel Не больше ... ключ:, 0.0107foreach:0.0217
SeanJA

Ответы:

1338

2019 Обновление

Начиная с PHP 7.3 , появилась новая встроенная функция, array_key_first()которая будет извлекать первый ключ из данного массива без сброса внутреннего указателя. Проверьте документацию для получения дополнительной информации.


Вы можете использовать resetи key:

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)
Blixt
источник
141
Как примечание, reset()также случается, что возвращается первый элемент (значение, а не ключ) любого массива, что также может быть удобно.
devios1
5
В документации есть комментарий, чтобы reset()сказать Don't use reset () `, чтобы получить первое значение ассоциативного массива. Он отлично работает для истинных массивов, но неожиданно работает с объектами Iterator. bugs.php.net/bug.php?id=38478 `Это все еще правда? Я в замешательстве
Дмитрий Пашкевич
13
@DmitryPashkevich: Не беспокойтесь об этом комментарии. Они говорят не об arrayобъектах, а о пользовательских объектах (которые не являются реальными массивами). Я предполагаю, что они запутали разницу в структурах данных, но в основном resetвозвращает значение первого «ключа», который для объектов был бы $propв примере, приведенном в отчете «ошибка», но для массива - первый ключ. Так что не волнуйтесь, пока вы используете реальные массивы (созданные с помощью array(…)), у вас не будет проблем.
Blixt
2
Следует отметить, что end () и reset () имеют побочный эффект. Тем не менее, большая часть кода в мире не полагается на внутренний указатель, так что это обычно не проблема.
Donquixote
1
@ user3019105 Существует только один внутренний указатель на массив, а это означает , что если какой - либо код за пределами функции изменяет его (по телефону next, reset, endили сквозным через массив), вы не получите ожидаемое значение при вызове key. Так что да, всегда звоните resetперед использованием, keyчтобы убедиться, что вы получите то, что хотите.
Blixt
80

array_keysвозвращает массив ключей. Возьми первую запись. В качестве альтернативы, вы можете вызвать resetмассив, а затем key. Последний подход, вероятно, немного быстрее (хотя я его не тестировал), но имеет побочный эффект сброса внутреннего указателя.

troelskn
источник
52
Просто (позднее) примечание для будущих читателей: последний подход не просто «немного» быстрее. Существует большая разница между итерацией всего массива, сохранением каждого ключа в другом вновь созданном массиве и запросом первого ключа массива в виде строки.
Blixt
3
Почему неэффективный foreach как оп в этом вопросе по сравнению со всеми этими ответами?
Эмилио Горт
5
@EmilioGort Хороший вопрос. Я не думаю, что есть разница в производительности foreach+ breakи reset+ на keyсамом деле. Но первое выглядит довольно странно, поэтому для стилистических вопросов я бы предпочел второе.
troelskn
@EmilioGort: Afaik, foreach () копирует массив внутренне. Таким образом, мы можем предположить, что это будет медленнее. (Было бы неплохо, если бы кто-то мог это подтвердить)
donquixote
3
@donquixote Я точно не знаю, но, предполагая, что это обычный массив (а не объект, реализующий какой-то интерфейс или интерфейс Iterator), я уверен, foreachчто не создает для него внутреннюю копию, а просто выполняет итерацию указателя , аналогично использованию более низкого уровня nextи currentт. д.
troelskn
54

Интересно, что цикл foreach на самом деле является наиболее эффективным способом сделать это.

Поскольку ОП конкретно спрашивает об эффективности, следует отметить, что все текущие ответы на самом деле гораздо менее эффективны, чем foreach.

Я сделал тест на это с php 5.4, и метод указателя сброса / ключа (принятый ответ), кажется, примерно в 7 раз медленнее, чем foreach. Другие подходы, манипулирующие всем массивом (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
foreach http://3v4l.org/gRoGD/perf#tabs

Webmut
источник
3
У вас есть где-нибудь эталонные тесты? Как то, как вы тестировали и так далее. В любом случае, спасибо за их запуск!
грипп
Я хотел бы указать на тот факт, что во всем тесте используется один и тот же массив. Я думаю, что этот факт существенно влияет на подход foreach. Как упомянуто в комментарии к некоторому ответу @donquixote выше - foreach внутренне копирует массив. Я могу себе представить, что эта копия используется повторно во время выполнения теста, поскольку предотвращение копирования в массиве повышает производительность только в этом тесте.
Jarda
2
@Jarda Начиная с php7, foreachникогда не копирует массив, если вы непосредственно не модифицируете его внутри цикла foreach. На php5 структура массива может быть скопирована в некоторых случаях (когда ее refcount> 1), и вы действительно правы, это может оказать существенное влияние. К счастью, нет ничего страшного на php7, где эта проблема была решена. Вот отличная статья о том, как foreach работает сейчас под капотом, и как он работал в прошлом.
Webmut
2
Начиная с php7.2, используя вышеуказанный тест, foreach по-прежнему самый быстрый
billynoah
36

key($an_array) даст вам первый ключ

edit per Blixt: вы должны вызвать reset($array);прежде, чем key($an_array)сбросить указатель на начало массива.

jimyi
источник
7
Помните, что указатель массива может не находиться на первом элементе, смотрите мой ответ.
Blixt
Я думаю, что этот ответ поможет моему случаю без сброса, потому что я сначала проверяю, что массив имеет только один элемент. Спасибо
groovenectar
24

Вы могли бы попробовать

array_keys($data)[0]
стопор
источник
22

Для 2018+

Начиная с PHP 7.3, есть array_key_first()функция, которая достигает именно этого:

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

Документация доступна здесь . 😉

ivanaugustobd
источник
21
list($firstKey) = array_keys($yourArray);
Сергей Соколенко
источник
2
Это, наверное, не самый эффективный.
Яда
3
@Яда, да, но это может быть заметно в редких случаях; в большинстве случаев удобочитаемость и ремонтопригодность имеют гораздо большее значение; и я также предпочитаю решение, которое не изменяет исходные объекты / массивы: например, reset ($ ar); $ key = key ($ ar); - не всегда хорошая идея, я бы предпочел выбрать решение MartyIX, которое является более лаконичным, чем мое, например: array_keys ($ ar) [0];
Сергей Соколенко
20

Если эффективность не так важна для вас, вы можете использовать array_keys($yourArray)[0]в PHP 5.4 (и выше).

Примеры:

# 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]Действителен ли синтаксис?
Трант
5
Это в PHP 5.4. Это называется array dereferencing. См. Например: schlueters.de/blog/archives/…
Мартин Всетичка
@trante, он действует на всех языках под солнцем, кроме PHP <5.4.
Pacerier
13

Пожалуйста, найдите следующее:

$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
Hamidreza
источник
1
@jurgemaister max()доза не возвращает первый ключ массива ассоциаций. max возвращает максимальное значение списка или массива элементов
Хамидреза
5
Не OP-запрос, но очень полезный в некоторых ситуациях.
д.раев
9

Это также может быть решением:

$yourArray = array('first_key'=> 'First', 2, 3, 4, 5);
$first_key = current(array_flip($yourArray));
echo $first_key;

Я проверил это, и это работает.

Рабочий код .

Ученик
источник
3
array_flip (): может переворачивать только значения STRING и INTEGER!
Мауро
5

Чтобы улучшить решение Webmut , я добавил следующее решение:

$firstKey = array_keys(array_slice($array, 0, 1, TRUE))[0];

Вывод для меня на PHP 7.1:

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, то результаты станут

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 

Время выполнения метода array_keys составляет 30 секунд (при использовании только 1000 элементов время для остальных операций было примерно таким же, но у метода array_keys было около 7,5 секунд).

PrinsEdje80
источник
3
 $arr = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
 list($first_key) = each($arr);
 print $first_key;
 // key1
voodoo417
источник
3

Лучший способ, который работал для меня, был

array_shift(array_keys($array))

array_keys получает массив ключей из исходного массива, а затем array_shiftвырезает из него значение первого элемента. Вам понадобится PHP 5.4+ для этого.

Юрий Петровский
источник
3

Это самый простой способ, который я когда-либо нашел. Быстро и всего две строчки кода :-D

$keys = array_keys($array);
echo $array[$keys[0]];
Сальви Паскуаль
источник
2

php73:

$array = ['a' => '..', 'b' => '..'];

array_key_first($array); // 'a'
array_key_last($array); // 'b';

http://php.net/manual/en/function.array-key-first.php

Бенджамин Беганович
источник
1
Включение объяснения действительно помогает улучшить качество вашего поста. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете свой код
MichaelvE
0

Однострочник:

$array = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
echo key( array_slice( $array, 0, 1, true ) );

# echos 'key1'
Коджа Бриз
источник
0

Сегодня мне пришлось искать первый ключ моего массива, возвращенный запросом POST. (И запишите номер для идентификатора формы и т. Д.)

Ну, я нашел это: вернуть первый ключ ассоциативного массива в PHP

http://php.net/key

Я сделал это, и это работает.

    $data = $request->request->all();
    dump($data);
    while ($test = current($data)) {
        dump($test);
        echo key($data).'<br />';die();
        break;
    }

Может быть, это будет 15 минут от другого парня. КДМ.

Рупиоз Клемент
источник
-2

Вы можете играть со своим массивом

$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и используя, как показано выше.

Priyank
источник
1
Это значения, а не ключи.
Виктор Шредер