Obter a primeira chave em um array associativo (possivelmente)?

756

Qual é a melhor maneira de determinar a primeira chave em uma matriz possivelmente associativa? Meu primeiro pensamento foi foreach da matriz e imediatamente quebrá-la, assim:

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

Assim, ter a chave $ contém a primeira chave, mas isso parece ineficiente. Alguém tem uma solução melhor?

Alex S
fonte
4
Por que é ineficiente foreach?
Emilio Gort
2
Comparado a todas as respostas, o foreach ainda é o FIDDLE mais rápido , PHP 5.3 , meu teste de host local no PHP 5.5 mostra que a diferença é um pouco a favor do foreach.
Danijel
3
@ Danijel, foreaché semanticamente errado.
Pacerier 17/02
2
@AlexS, each($arr)['key']ou each($arr)[0]funcionaria.
Pacerier 17/02
1
@Danijel Não é mais ... key 0.01070.0217
:,

Respostas:

1337

Atualização de 2019

A partir do PHP 7.3 , existe uma nova função array_key_first()interna chamada que recuperará a primeira chave da matriz fornecida sem redefinir o ponteiro interno. Confira a documentação para mais informações.


Você pode usar resete key:

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

É essencialmente o mesmo que o seu código inicial, mas com um pouco menos de sobrecarga e é mais óbvio o que está acontecendo.

Lembre-se de ligar reset, ou você pode obter qualquer uma das chaves da matriz. Você também pode usar em endvez de resetpara obter a última chave.

Se você queria que a chave obtivesse o primeiro valor, resetna verdade , ele a retornaria:

$first_value = reset($array);

No entanto, há um caso especial a ser observado (verifique primeiro o comprimento da matriz):

$arr1 = array(false);
$arr2 = array();
var_dump(reset($arr1) === reset($arr2)); // bool(true)
Blixt
fonte
141
Como uma observação lateral, reset()também retorna o primeiro elemento (valor, não chave) de qualquer matriz, o que também pode ser útil.
devios1
5
Há um comentário na documentação reset()dizendo Don't use reset () `para obter o primeiro valor de uma matriz associativa. Funciona muito bem para matrizes verdadeiras, mas funciona inesperadamente em objetos Iterator. bugs.php.net/bug.php?id=38478 `Isso ainda é verdade? Estou confuso
Dmitry Pashkevich
13
@DmitryPashkevich: Não se preocupe com esse comentário. Eles não estão falando sobre arrayobjetos, mas objetos personalizados (que não são matrizes reais). Eu acho que eles confundiram a diferença nas estruturas de dados, mas basicamente resetretornam o valor da primeira "chave", que para objetos seria $propo exemplo dado no relatório "bug", mas para uma matriz a primeira chave. Portanto, não se preocupe, desde que você use matrizes reais (criadas com array(…)), você não terá problemas.
Blixt 23/01
2
Deve-se mencionar que end () e reset () têm um efeito colateral. No entanto, a maioria dos códigos no mundo não depende do ponteiro interno estar em qualquer lugar, portanto, isso geralmente não é um problema.
Donquixote
1
@ user3019105 Há apenas um ponteiro interno por matriz, o que significa que se qualquer código fora de sua função muda (chamando next, reset, endou loop através da matriz), você não vai obter o valor esperado quando você chamar key. Portanto, sim, sempre ligue resetantes de usar keypara ter certeza de que consegue o que deseja.
Blixt
80

array_keysretorna uma matriz de chaves. Pegue a primeira entrada. Como alternativa, você pode chamar reseta matriz e, posteriormente key. A última abordagem é provavelmente um pouco mais rápida (Thoug, eu não a testei), mas tem o efeito colateral de redefinir o ponteiro interno.

Troelskn
fonte
52
Apenas uma nota (tardia) para futuros leitores sobre isso: A última abordagem não é apenas "um pouco" mais rápida. Há uma grande diferença entre iterar uma matriz inteira, armazenar todas as chaves em outra matriz recém-criada e solicitar a primeira chave de uma matriz como uma string.
Blixt 4/09/09
3
Por que ineficiente foreach como o op na pergunta se compara a todas essas respostas?
Emilio Gort
5
@EmilioGort Good question. Não acho que exista diferença no desempenho de foreach+ breake reset+ keyna verdade. Mas o primeiro parece um pouco estranho, então, por questões estilísticas, eu preferiria o segundo.
troelskn
@EmilioGort: Afaik, foreach () copia a matriz internamente. Então, podemos assumir que é mais lento. (Seria bom se alguém pudesse confirmar que)
Donquixote
3
@donquixote Não sei ao certo, mas supondo que seja uma matriz regular (e não um objeto implementando algum tipo ou interface Iterator), tenho certeza de foreachque não cria uma cópia interna para ele, mas apenas itera um ponteiro , semelhante ao uso do mais baixo nível next, currentetc
troelskn
54

Curiosamente, o loop foreach é realmente a maneira mais eficiente de fazer isso.

Como o PO perguntou especificamente sobre eficiência, deve-se ressaltar que todas as respostas atuais são de fato muito menos eficientes do que uma pesquisa.

Fiz uma referência nisso com o php 5.4, e o método de reset / key pointer (resposta aceita) parece ser cerca de 7 vezes mais lento que um foreach. Outras abordagens manipulando toda a matriz (array_keys, array_flip) são obviamente ainda mais lentas que isso e se tornam muito piores ao trabalhar com uma matriz grande.

O Foreach não é ineficiente, fique à vontade para usá-lo!

Editar 03-03-2015:

Scripts de benchmark foram solicitados, eu não tenho os originais, mas fiz alguns novos testes. Dessa vez, encontrei o foreach apenas duas vezes mais rápido que a tecla reset /. Usei uma matriz de 100 chaves e executei cada método um milhão de vezes para obter alguma diferença perceptível, aqui está o código da referência simples:

$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 />";

No meu php 5.5 esta saída:

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

tecla reset + http://3v4l.org/b4DrN/perf#tabs
foreach http://3v4l.org/gRoGD/perf#tabs

Webmut
fonte
3
Você tem os benchmarks em algum lugar. Como você testou etc. De qualquer forma, obrigado por executá-los!
gripe
Gostaria de salientar o fato de que existe a mesma matriz usada durante todo o teste. Eu acho que esse fato influencia significativamente a abordagem foreach. Como @donquixote mencionado no comentário para algumas respostas acima - foreach copia internamente a matriz. Eu posso imaginar que essa cópia seja reutilizada durante a execução do benchmark, pois evitar a cópia de matriz aprimora o desempenho apenas dentro deste teste.
Jarda
2
@Jarda A partir do php7, foreachnunca copia a matriz, a menos que você a modifique diretamente dentro do loop foreach. No php5, a estrutura do array pode ser copiada em alguns casos (quando seu refcount> 1) e você está certo, pode haver uma influência significativa lá. Felizmente, não há nada com que se preocupar no php7, onde esse problema foi resolvido. Aqui está uma ótima leitura sobre como o foreach funciona sob o capô agora e como funcionou no passado.
WebMut
2
a partir de php7.2 usando o benchmark acima, foreach ainda mais rápido é
billynoah
36

key($an_array) vai te dar a primeira chave

editar por Blixt: você deve ligar reset($array);antes key($an_array)para redefinir o ponteiro para o início da matriz.

jimyi
fonte
7
Lembre-se de que o ponteiro da matriz pode não estar no primeiro elemento, veja minha resposta.
Blixt 22/06/09
Acho que essa resposta ajudará meu caso sem redefinir, porque primeiro garanto que a matriz tenha apenas um elemento. Obrigado
groovenectar 10/09/14
23

Você poderia tentar

array_keys($data)[0]
Rolha
fonte
22

Para 2018 +

A partir do PHP 7.3, existe uma array_key_first()função que consegue exatamente isso:

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

A documentação está disponível aqui . 😉

ivanaugustobd
fonte
21
list($firstKey) = array_keys($yourArray);
Sergiy Sokolenko
fonte
2
Provavelmente não é o mais eficiente.
Yada
3
@ Yada, sim, mas isso pode ser notado em casos raros; na maioria dos casos, a legibilidade e a manutenção são de uma importância muito maior; e também prefiro uma solução que não modifique objetos / matrizes originais: por exemplo, reset ($ ar); $ chave = chave ($ ar); - nem sempre é uma boa ideia, prefiro escolher a solução do MartyIX, que é mais concisa que a minha, por exemplo: array_keys ($ ar) [0];
Sergiy Sokolenko
20

Se a eficiência não é tão importante para você, você pode usar array_keys($yourArray)[0]no PHP 5.4 (e superior).

Exemplos:

# 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"

A vantagem sobre a solução:

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

é que você pode passar array_keys($arr)[0]como um parâmetro de função (ie doSomething(array_keys($arr)[0], $otherParameter)).

HTH

Martin Vseticka
fonte
3
A array_keys($arr)[0]sintaxe é válida?
Trante 17/05
5
Está no PHP 5.4. É chamado array dereferencing. Veja, por exemplo: schlueters.de/blog/archives/…
Martin Vseticka
@trante, é válido em todas as línguas sob o sol, exceto PHP <5.4.
Pacerier 17/02
13

Por favor, encontre o seguinte:

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

Exemplo de trabalho:

Aluno
fonte
12
$myArray = array(
    2 => '3th element',
    4 => 'first element',
    1 => 'second element',
    3 => '4th element'
);
echo min(array_keys($myArray)); // return 1
Hamidreza
fonte
1
A max()dose @jurgemaister não retorna a primeira chave de uma matriz assoc. max valor máximo retorno de uma lista ou um array itens
Hamidreza
5
Não é a solicitação do OP, mas é muito útil em algumas situações.
d.raev
9

Isso também pode ser uma solução:

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

Eu testei e funciona.

Código de trabalho .

Aluno
fonte
3
array_flip (): só pode inverter os valores STRING e INTEGER!
Mauro
5

Para aprimorar a solução do Webmut , adicionei a seguinte solução:

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

A saída para mim no 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 

Se eu fizer isso para uma matriz de tamanho 10000, os resultados se tornarão

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 

O método array_keys atinge o tempo limite em 30 segundos (com apenas 1000 elementos, o tempo para o resto foi praticamente o mesmo, mas o método array_keys teve cerca de 7,5 segundos).

PrinsEdje80
fonte
3
 $arr = array('key1'=>'value1','key2'=>'value2','key3'=>'key3');
 list($first_key) = each($arr);
 print $first_key;
 // key1
voodoo417
fonte
3

A melhor maneira que funcionou para mim foi

array_shift(array_keys($array))

array_keys obtém uma matriz de chaves da matriz inicial e depois array_shiftcorta o primeiro valor do elemento. Você precisará do PHP 5.4+ para isso.

Yuriy Petrovskiy
fonte
3

Esta é a maneira mais fácil que eu já encontrei. Rápido e apenas duas linhas de código :-D

$keys = array_keys($array);
echo $array[$keys[0]];
Salvi Pascual
fonte
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

Benjamin Beganović
fonte
1
Incluir uma explicação realmente ajuda a melhorar a qualidade da sua postagem. Lembre-se de que você está respondendo à pergunta dos leitores no futuro e essas pessoas podem não saber os motivos da sua sugestão de código.
MichaelvE
0

Uma linha:

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

# echos 'key1'
Kohjah Breese
fonte
0

Hoje tive que procurar a primeira chave da minha matriz retornada por uma solicitação POST. (E anote o número da identificação do formulário, etc.)

Bem, eu encontrei o seguinte: Retorne a primeira chave do array associativo em PHP

http://php.net/key

Eu fiz isso e funcionou.

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

Talvez seja eco 15min de outro cara. CYA.

Roupioz Clement
fonte
-2

Você pode jogar com sua matriz

$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';

Para obter o primeiro elemento da matriz, você pode usar currente, para o último elemento, você pode usarend

Editar

Por uma questão de não obter mais votos negativos para a resposta, você pode converter sua chave em valor usando array_keyse usando como mostrado acima.

Priyank
fonte
1
Estes são valores, não chaves.
Victor Schröder