Lấy khóa đầu tiên trong một mảng kết hợp (có thể)?


756

Cách tốt nhất để xác định khóa đầu tiên trong một mảng có thể kết hợp là gì? Đầu tiên tôi nghĩ rằng nó chỉ tìm kiếm mảng và sau đó phá vỡ nó ngay lập tức, như thế này:

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

Do đó, có khóa $ chứa khóa đầu tiên, nhưng điều này có vẻ không hiệu quả. Có ai có một giải pháp tốt hơn?


4
Tại sao foreach không hiệu quả?
Emilio Gort

2
So với tất cả các câu trả lời, foreach vẫn là FIDDLE nhanh nhất , PHP 5.3 , thử nghiệm localhost của tôi trên PHP 5.5 cho thấy sự khác biệt có phần nghiêng về foreach.
Danijel

3
@Danijel, foreachlà sai về mặt ngữ nghĩa.
Pacerier 17/2/2015

2
@AlexS, Hoặc each($arr)['key']hoặc each($arr)[0]sẽ làm việc.
Pacerier 17/2/2015

1
@Danijel Không còn nữa ... key : 0.0107, foreach:0.0217
SeanJA

Câu trả lời:


1337

Cập nhật 2019

Bắt đầu từ PHP 7.3 , có một hàm dựng sẵn mới được gọi là array_key_first()sẽ lấy khóa đầu tiên từ mảng đã cho mà không đặt lại con trỏ bên trong. Kiểm tra các tài liệu để biết thêm.


Bạn có thể sử dụng resetkey:

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

Về cơ bản, nó giống như mã ban đầu của bạn, nhưng với chi phí thấp hơn một chút và rõ ràng hơn những gì đang xảy ra.

Chỉ cần nhớ gọi reset, hoặc bạn có thể nhận được bất kỳ phím nào trong mảng. Bạn cũng có thể sử dụng endthay vì resetđể lấy chìa khóa cuối cùng.

Nếu bạn muốn khóa nhận giá trị đầu tiên, hãy resettrả về nó:

$first_value = reset($array);

Có một trường hợp đặc biệt cần chú ý mặc dù (vì vậy hãy kiểm tra độ dài của mảng trước):

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

141
Như một lưu ý phụ, reset()cũng xảy ra để trả về phần tử đầu tiên (giá trị, không phải khóa) của bất kỳ mảng nào, điều này cũng có thể có ích.
devios1

5
Có một nhận xét trong các tài liệu để reset()nói Don't use reset () `để lấy giá trị đầu tiên của một mảng kết hợp. Nó hoạt động tuyệt vời cho các mảng thực sự nhưng hoạt động bất ngờ trên các đối tượng Iterator. bug.php.net/orms.php?id=38478 `Điều đó có còn đúng không? Tôi bối rối
Dmitry Pashkevich

13
@DmitryPashkevich: Đừng lo lắng về nhận xét đó. Họ không nói về arraycác đối tượng, mà là các đối tượng tùy chỉnh (đó không phải là mảng thực tế). Tôi đoán rằng họ có sự khác biệt về cấu trúc dữ liệu bị nhầm lẫn, nhưng về cơ bản, resettrả về giá trị của "khóa" đầu tiên, đối với các đối tượng sẽ có $proptrong ví dụ được đưa ra trong báo cáo "lỗi", nhưng đối với một mảng là khóa đầu tiên. Vì vậy, đừng lo lắng, miễn là bạn sử dụng mảng thực (được tạo bằng array(…)), bạn sẽ không gặp vấn đề gì.
Blixt

2
Cần phải đề cập rằng end () và reset () có tác dụng phụ. Tuy nhiên, hầu hết các mã trên thế giới không dựa vào con trỏ bên trong ở bất cứ đâu, vì vậy điều này thường không phải là vấn đề.
donquixote

1
@ user3019105 Chỉ có một con trỏ bên trong mỗi mảng, có nghĩa là nếu bất kỳ mã bên ngoài chức năng của bạn thay đổi nó (bằng cách gọi next, reset, endhoặc lặp qua mảng), bạn sẽ không nhận được giá trị mong đợi khi bạn gọi key. Vì vậy, có, luôn luôn gọi resettrước khi sử dụng keyđể chắc chắn bạn có được những gì bạn muốn.
Blixt

80

array_keystrả về một mảng các khóa Đi vào mục đầu tiên. Ngoài ra, bạn có thể gọi resettrên mảng, và sau đó key. Cách tiếp cận thứ hai có thể nhanh hơn một chút (Thoug tôi đã không kiểm tra nó), nhưng nó có tác dụng phụ là đặt lại con trỏ bên trong.


52
Chỉ là một lưu ý (muộn) cho những độc giả tương lai về điều này: Cách tiếp cận sau không chỉ là "hơi" nhanh hơn. Có một sự khác biệt lớn giữa việc lặp lại toàn bộ một mảng, lưu trữ mọi khóa trong một mảng mới được tạo khác và yêu cầu khóa đầu tiên của một mảng là một chuỗi.
Blixt

3
Tại sao các bài giảng không hiệu quả như op có trong câu hỏi so với tất cả các câu trả lời này?
Emilio Gort

5
@EmilioGort Câu hỏi hay. Tôi không nghĩ có bất kỳ sự khác biệt nào trong hiệu suất của foreach+ breakreset+ keytrên thực tế. Nhưng cái trước trông khá kỳ lạ, vì vậy đối với các vấn đề về phong cách, tôi sẽ thích cái sau hơn.
troelskn

@EmilioGort: Afaik, foreach () sao chép mảng bên trong. Vì vậy, chúng ta có thể giả định nó sẽ chậm hơn. (Sẽ thật tuyệt nếu ai đó có thể xác nhận điều đó)
donquixote

3
@donquixote Tôi không biết chắc chắn, nhưng giả sử đó là một mảng thông thường (và không phải là một đối tượng thực hiện giao diện Iterator nào đó), tôi khá chắc chắn foreachkhông tạo ra một bản sao nội bộ cho nó, mà chỉ lặp đi lặp lại một con trỏ , tương tự như sử dụng cấp độ thấp hơn next, currentv.v.
troelskn

54

Thật thú vị, vòng lặp foreach thực sự là cách hiệu quả nhất để làm điều này.

Vì OP đặc biệt hỏi về hiệu quả, nên cần chỉ ra rằng tất cả các câu trả lời hiện tại trên thực tế kém hiệu quả hơn nhiều so với một bài giảng.

Tôi đã thực hiện một điểm chuẩn về điều này với php 5.4 và phương thức thiết lập lại con trỏ / phím (câu trả lời được chấp nhận) dường như chậm hơn khoảng 7 lần so với một bài giảng. Các cách tiếp cận khác thao túng toàn bộ mảng (Array_keys, Array_flip) rõ ràng thậm chí còn chậm hơn thế và trở nên tồi tệ hơn nhiều khi làm việc với một mảng lớn.

Foreach không hiệu quả chút nào, hãy sử dụng nó!

Chỉnh sửa 2015/03/03:

Các kịch bản điểm chuẩn đã được yêu cầu, tôi không có các kịch bản gốc nhưng thay vào đó đã thực hiện một số thử nghiệm mới. Lần này tôi thấy foreach chỉ nhanh gấp đôi tốc độ reset / key. Tôi đã sử dụng một mảng 100 khóa và chạy mỗi phương thức một triệu lần để có một số khác biệt đáng chú ý, đây là mã của điểm chuẩn đơn giản:

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

Trên php 5.5 của tôi, kết quả này:

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

đặt lại + khóa http://3v4l.org/b4DrN/perf#tabs
foreach http://3v4l.org/gRoGD/perf#tabs


3
Bạn có điểm chuẩn ở đâu đó không. Giống như cách bạn đã kiểm tra, vv Dù sao, cảm ơn bạn đã chạy chúng!
cúm

Tôi muốn chỉ ra một thực tế rằng, có cùng một mảng được sử dụng trong toàn bộ bài kiểm tra. Tôi nghĩ rằng thực tế này ảnh hưởng đáng kể đến phương pháp foreach. Như @donquixote đã đề cập trong bình luận cho một số phản hồi ở trên - foreach sao chép nội bộ mảng. Tôi có thể tưởng tượng rằng bản sao này được sử dụng lại trong khi chạy điểm chuẩn vì việc tránh sao chép mảng chỉ tăng cường hiệu suất trong thử nghiệm này.
Jarda

2
@Jarda Kể từ php7, foreachkhông bao giờ sao chép mảng trừ khi bạn trực tiếp sửa đổi nó trong vòng lặp foreach. Trên php5, cấu trúc mảng có thể được sao chép trong một số trường hợp (khi tổng số của nó> 1) và bạn thực sự đúng, nó có thể là một ảnh hưởng đáng kể ở đó. May mắn thay, không có gì phải lo lắng về php7, nơi vấn đề này đã được giải quyết. Đây là một bài đọc tuyệt vời cả về cách thức hoạt động của foreach bây giờ và cách nó hoạt động trong quá khứ.
Webmut

2
kể từ khi php7.2 sử dụng điểm chuẩn trên, foreach vẫn nhanh nhất
billynoah

36

key($an_array) sẽ cung cấp cho bạn chìa khóa đầu tiên

chỉnh sửa theo Blixt: bạn nên gọi reset($array);trước key($an_array)để đặt lại con trỏ về đầu mảng.


7
Hãy nhớ rằng con trỏ của mảng có thể không ở phần tử đầu tiên, xem câu trả lời của tôi.
Blixt

Tôi nghĩ rằng câu trả lời này sẽ giúp trường hợp của tôi mà không cần thiết lập lại bởi vì trước tiên tôi chắc chắn rằng mảng chỉ có một phần tử. Cảm ơn
Groovenectar


22

Đối với năm 2018+

Bắt đầu với PHP 7.3, có một array_key_first()chức năng đạt được chính xác điều này:

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

Tài liệu có sẵn ở đây . 😉


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

2
Đây có lẽ không phải là hiệu quả nhất.
Yada

3
@Yada, vâng, nhưng điều này có thể đáng chú ý trong những trường hợp hiếm hoi; trong hầu hết các trường hợp, khả năng đọc và bảo trì có tầm quan trọng lớn hơn nhiều; và tôi cũng thích giải pháp không làm thay đổi các đối tượng / mảng gốc: vd: reset ($ ar); $ key = key ($ ar); - không phải lúc nào cũng là ý tưởng hay, tôi muốn chọn giải pháp của MartyIX ngắn gọn hơn của tôi, ví dụ: Array_keys ($ ar) [0];
Sergiy Sokolenko

20

Nếu hiệu quả không quan trọng đối với bạn, bạn có thể sử dụng array_keys($yourArray)[0]trong PHP 5.4 (và cao hơn).

Ví dụ:

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

Ưu điểm so với giải pháp:

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

là bạn có thể vượt qua array_keys($arr)[0]như một tham số hàm (tức là doSomething(array_keys($arr)[0], $otherParameter)).

HTH


3
Liệu array_keys($arr)[0]cú pháp là hợp lệ?
trante

5
Nó nằm trong PHP 5.4. Nó được gọi là array dereferencing. Xem ví dụ: schlueter.de/blog/archives/ Kẻ
Martin Vseticka

@trante, Nó hợp lệ trong mọi ngôn ngữ dưới ánh mặt trời ngoại trừ PHP <5.4.
Pacerier 17/2/2015


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()liều không trả lại khóa đầu tiên của một mảng PGS. giá trị tối đa trả về tối đa của một danh sách hoặc một mục mảng
Hamidreza

5
Không phải yêu cầu OP, nhưng rất hữu ích trong một số tình huống.
d.raev

9

Đây cũng có thể là một giải pháp:

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

Tôi đã thử nó và nó hoạt động.

Mã làm việc .


3
mảng_flip (): Chỉ có thể lật các giá trị STRING và INTEGER!
Mauro

5

Để nâng cao giải pháp của Webmut , tôi đã thêm giải pháp sau:

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

Đầu ra cho tôi trên PHP 7.1 là:

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 

Nếu tôi làm điều này cho một mảng có kích thước 10000, thì kết quả sẽ trở thành

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 

Phương thức Array_keys hết thời gian sau 30 giây (chỉ có 1000 phần tử, thời gian cho phần còn lại là như nhau, nhưng phương thức Array_keys có khoảng 7,5 giây).


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

3

Cách tốt nhất làm việc cho tôi là

array_shift(array_keys($array))

array_keys lấy mảng các khóa từ mảng ban đầu và sau đó array_shiftcắt từ giá trị phần tử đầu tiên. Bạn sẽ cần PHP 5.4+ cho việc này.


3

Đây là cách dễ dàng hơn tôi từng tìm thấy. Nhanh và chỉ có hai dòng mã :-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/feft.array-key-first.php


1
Bao gồm một lời giải thích thực sự giúp cải thiện chất lượng bài viết của bạn. Hãy nhớ rằng bạn sẽ trả lời câu hỏi cho độc giả trong tương lai và những người đó có thể không biết lý do cho đề xuất mã của bạn
MichaelvE

0

Một lớp lót:

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

# echos 'key1'

0

Hôm nay tôi đã phải tìm kiếm khóa đầu tiên của mảng của tôi được trả về bởi một yêu cầu POST. (Và lưu ý số cho id mẫu, v.v.)

Chà, tôi đã tìm thấy điều này: Trả về khóa đầu tiên của mảng kết hợp trong PHP

http://php.net/key

Tôi đã làm điều này, và nó hoạt động.

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

Có lẽ nó sẽ sinh thái 15 phút của một anh chàng khác. CYA.


-2

Bạn có thể chơi với mảng của bạn

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

Để có được phần tử đầu tiên của mảng, bạn có thể sử dụng currentvà cho phần tử cuối cùng bạn có thể sử dụngend

Biên tập

Chỉ vì lý do không nhận được thêm phiếu bầu cho câu trả lời, bạn có thể chuyển đổi khóa của mình thành giá trị sử dụng array_keysvà sử dụng như được hiển thị ở trên.


1
Đây là các giá trị, không phải là khóa.
Victor Schröder
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.