PHP memperlakukan semua array sebagai asosiatif, jadi tidak ada fungsi bawaan. Adakah yang bisa merekomendasikan cara yang cukup efisien untuk memeriksa apakah array hanya berisi kunci numerik?
Pada dasarnya, saya ingin dapat membedakan antara ini:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
dan ini:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, yang sederhana dan cepat. Tentu saja, Anda harus terlebih dahulu memastikan array tidak kosong, dan Anda harus memiliki pengetahuan tentang kemungkinan isi array sehingga metode tidak bisa gagal (seperti angka campuran / asosiatif, atau non-sekuensial).Jawaban:
Anda telah mengajukan dua pertanyaan yang tidak cukup setara:
Pertimbangkan perilaku mana yang benar-benar Anda butuhkan. (Mungkin itu akan dilakukan untuk tujuan Anda.)
Pertanyaan pertama (cukup memeriksa bahwa semua kunci adalah angka) dijawab dengan baik oleh Kapten kurO .
Untuk pertanyaan kedua (memeriksa apakah array berindeks nol dan berurutan), Anda dapat menggunakan fungsi berikut:
sumber
isSequential()
akan lebih masuk akal daripadaisAssoc()
. Dalam fungsi seperti itu, array kosong harus dilihat sebagai berurutan. Rumusnya bisaarray() === $arr || !isAssoc($arr)
.array_key_exists
alih-alihisset
karena jika elemen nol adalah nilai nol, penerbit akan mengembalikan false salah. Nilai nol biasanya harus menjadi nilai yang sah dalam array tersebut.Untuk sekadar memeriksa apakah array memiliki kunci non-integer (bukan apakah array diindeks secara berurutan atau diindeks nol):
Jika setidaknya ada satu kunci string,
$array
akan dianggap sebagai array asosiatif.sumber
$isIndexed = array_values($arr) === $arr;
? Yang saya tanyakan: bagaimana menurut Andaarray_values()
berfungsi? Bagaimana menurut Anda===
diterapkan pada array bekerja? Jawabannya tentu saja mereka juga beralih ke array.var_dump([1.2 => 'foo', 1.5 => 'bar']);
Anda akan menemukan bahwa Anda mendapatkan array[1 => 'bar']
. Tidak ada cara apa pun untuk mengetahui tipe asli kunci. Ya, semua ini mengerikan; Array PHP sejauh ini merupakan bagian terburuk dari bahasa, dan sebagian besar kerusakan tidak dapat diperbaiki dan berutang pada gagasan untuk menggunakan konstruksi tunggal untuk array tradisional dan hashmap tradisional menjadi yang mengerikan dari awal.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
akan menjadifalse
(array berurutan) sedangkan seharusnyatrue
(array asosiatif). toolsqa.com/data-structures/array-in-programming Saya tidak yakin apakah kuncinya harus naik urutan? (0, 1, ...)Tentunya ini adalah alternatif yang lebih baik.
sumber
===
akan membuang waktu memeriksa apakah nilainya sama, meskipun kami hanya tertarik pada kunci. Untuk alasan ini saya lebih suka$k = array_keys( $arr ); return $k === array_keys( $k );
versi.Banyak komentator dalam pertanyaan ini tidak mengerti bagaimana array bekerja di PHP. Dari dokumentasi array :
Dengan kata lain, tidak ada yang namanya kunci array "8" karena akan selalu (diam-diam) dikonversi ke bilangan bulat 8. Jadi mencoba untuk membedakan antara bilangan bulat dan string numerik tidak perlu.
Jika Anda ingin cara yang paling efisien untuk memeriksa array untuk kunci non-integer tanpa membuat salinan bagian dari array (seperti array_keys () tidak) atau semuanya (seperti foreach tidak):
Ini berfungsi karena kunci () mengembalikan NULL ketika posisi array saat ini tidak valid dan NULL tidak pernah bisa menjadi kunci yang valid (jika Anda mencoba menggunakan NULL sebagai kunci array, ia akan dikonversi secara diam-diam ke "").
sumber
0
hinggacount($array)-1
, dalam urutan yang ketat ini. Pemeriksaan pendahuluan denganis_array()
dapat membantu. Tambahkan variabel yang meningkat untuk memeriksa urutan kunci:for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
Itu menyelesaikan kesepakatan.foreach
alih-alih iterasi eksplisit sekitar dua kali lebih cepat.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Sebagaimana dinyatakan oleh OP :
itu tidak cukup masuk akal (IMHO) untuk menulis fungsi yang memeriksa apakah array asosiatif . Jadi hal pertama yang pertama: apa yang merupakan kunci dalam array PHP ?:
Itu berarti ada 3 kemungkinan kasus:
Kami dapat memeriksa setiap kasus dengan fungsi-fungsi berikut.
Kasus 1: semua kunci berupa angka / bilangan bulat .
Catatan : Fungsi ini mengembalikan true untuk array kosong juga.
Kasus 2: semua kunci adalah string .
Catatan : Fungsi ini mengembalikan true untuk array kosong juga.
Kasus 3. beberapa kunci adalah string , beberapa kunci adalah numerik / bilangan bulat .
Catatan : Fungsi ini mengembalikan true untuk array kosong juga.
Oleh karena itu:
(yang menurut definisi, seperti dalam " set kosong adalah subset dari setiap set A karena semua elemen milik A ").
Sekarang, untuk sebuah array menjadi array "asli" yang kita semua terbiasa, artinya:
Kami dapat memeriksa dengan fungsi berikut.
Kasus 3a. kunci numerik / bilangan bulat , berurutan , dan berbasis nol .
Catatan : Fungsi ini mengembalikan true untuk array kosong juga.
Peringatan / Kesalahan (atau, fakta lebih aneh tentang kunci array di PHP)
Kunci integer
Kunci untuk array ini adalah bilangan bulat :
Kunci dawai
Kunci untuk array ini adalah string :
Kunci integer yang terlihat seperti string
Jika Anda pikir kunci dalam
array("13" => "b")
adalah string , Anda salah . Dari dokumen di sini :Misalnya, kunci untuk array ini adalah bilangan bulat :
Tetapi kunci untuk array ini adalah string :
Terlebih lagi, menurut dokter ,
Jadi kunci untuk array ini mungkin atau tidak mungkin menjadi bilangan bulat - itu tergantung pada platform Anda.
Lebih buruk lagi, PHP cenderung bermasalah jika integer mendekati angka 2 31 = 2.147.483.648 (lihat bug 51430 , bug 52899 ). Sebagai contoh, pada lingkungan lokal saya (PHP 5.3.8 pada XAMPP 1.7.7 pada Windows 7),
var_dump(array("2147483647" => "b"))
berikantetapi pada demo langsung ini pada codepad (PHP 5.2.5), ekspresi yang sama memberikan
Jadi kuncinya adalah integer di satu lingkungan tetapi string di yang lain, meskipun
2147483647
adalah 32-bit yang ditandatangani integer .sumber
Dari segi kecepatan:
Memori-bijaksana:
sumber
sumber
array('1'=>'asdf', '2'=>'too')
akan dianggap sebagai array asosiatif sementara sebenarnya tidak (kunci sebenarnya string)true
jika tombolnya adalah: nol, bilangan bulat (hanya positif), string kosong, atau kombinasi apa pun di atas, seperti string "09". Fungsi ini tidak memperhitungkan urutan tombol. Jadiarray(0=>'blah', 2=>'yep', 3=>'wahey')
,array(0=>'blah', 2=>'yep', 1=>'wahey')
danarray('blah', 'yep', 'wahey')
semuanya asosiatif menurut fungsi ini, sementaraarray('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')
tidak.Sebenarnya cara yang paling efisien adalah sebagai berikut:
Ini berfungsi karena membandingkan kunci (yang untuk array berurutan selalu 0,1,2 dll) dengan kunci tombol (yang akan selalu menjadi 0,1,2 dll).
sumber
true
untukarray(1=>"a")
tetapifalse
untukarray("a"=>"a")
. Akan lebih bermakna jika!=
digantikan oleh!==
.[0] == ['a']
di PHP (sejak0 == 'a'
, dan, memang,0 == 'banana'
). Operator PHP==
gila.Saya telah menggunakan keduanya
array_keys($obj) !== range(0, count($obj) - 1)
danarray_values($arr) !== $arr
(yang merupakan dual dari satu sama lain, meskipun yang kedua lebih murah daripada yang pertama) tetapi keduanya gagal untuk array yang sangat besar.Ini karena
array_keys
danarray_values
keduanya merupakan operasi yang sangat mahal (karena mereka membangun array ukuran baru yang kira-kira sama dengan aslinya).Fungsi berikut ini lebih kuat daripada metode yang disediakan di atas:
Perhatikan juga bahwa jika Anda tidak ingin membedakan array jarang dari array asosiatif, Anda cukup kembali
'assoc'
dari keduaif
blok.Akhirnya, walaupun ini mungkin tampak kurang "elegan" daripada banyak "solusi" pada halaman ini, dalam praktiknya ini jauh lebih efisien. Hampir semua array asosiatif akan terdeteksi secara instan. Hanya array yang diindeks yang akan diperiksa secara mendalam, dan metode yang diuraikan di atas tidak hanya memeriksa array yang diindeks secara mendalam, mereka juga menggandakannya.
sumber
Saya pikir dua fungsi berikut adalah cara terbaik untuk memeriksa 'jika array asosiatif atau numerik'. Karena 'numerik' dapat berarti hanya tombol angka atau hanya tombol angka berurutan, dua fungsi tercantum di bawah ini yang memeriksa kedua kondisi:
Fungsi pertama memeriksa apakah setiap kunci adalah nilai integer. Fungsi kedua memeriksa apakah setiap kunci adalah nilai integer dan selain itu memeriksa apakah semua kunci berurutan mulai dari $ base, yang defaultnya ke 0 dan dengan demikian dapat dihilangkan jika Anda tidak perlu menentukan nilai basis lain. key ($ my_array) mengembalikan null jika read pointer dipindahkan melewati akhir array, yang mengakhiri loop for dan membuat pernyataan setelah for loop mengembalikan true jika semua kunci integer. Jika tidak, loop berakhir prematur karena kunci bertipe string, dan pernyataan setelah for loop akan mengembalikan false. Fungsi terakhir di samping menambahkan satu ke $ basis setelah setiap perbandingan, untuk dapat memeriksa apakah kunci berikutnya adalah nilai yang benar. Perbandingan ketat membuatnya juga memeriksa apakah kuncinya adalah tipe integer. Bagian $ base = (int) $ base di bagian pertama loop for dapat ditinggalkan ketika $ base dihilangkan atau jika Anda memastikan itu hanya disebut menggunakan integer. Tetapi karena saya tidak bisa memastikan untuk semua orang, saya meninggalkannya. Pernyataan itu hanya dieksekusi sekali saja. Saya pikir ini adalah solusi yang paling efisien:
Ingat bahwa kunci array hanya bisa berupa integer atau string, dan string numerik seperti "1" (tetapi bukan "01") akan diterjemahkan menjadi integer. Itulah yang membuat memeriksa kunci integer satu-satunya operasi yang diperlukan selain menghitung jika Anda ingin array berurutan. Secara alami, jika is_indexed_array mengembalikan false, array dapat dianggap asosiatif. Saya katakan 'terlihat', karena sebenarnya mereka semua.
sumber
Fungsi ini dapat menangani:
idenya sederhana: jika salah satu kunci BUKAN bilangan bulat, itu adalah array asosiatif, jika tidak itu berurutan.
sumber
Saya memperhatikan dua pendekatan populer untuk pertanyaan ini: satu menggunakan
array_values()
dan lainnya menggunakankey()
. Untuk mengetahui mana yang lebih cepat, saya menulis sebuah program kecil:Output untuk program pada PHP 5.2 di CentOS adalah sebagai berikut:
Output pada PHP 5.3 menghasilkan hasil yang serupa. Jelas menggunakan
array_values()
jauh lebih cepat.sumber
$arrays = Array( 'Array #1' => range(0, 50000), );
Salah satu cara untuk mendekati ini adalah dengan mendukung
json_encode
, yang sudah memiliki metode internal sendiri untuk membedakan antara array asosiatif dan array yang diindeks untuk menghasilkan JSON yang benar.Anda dapat melakukan ini dengan memeriksa untuk melihat apakah karakter pertama yang dikembalikan setelah pengkodean adalah
{
(array asosiatif) atau[
(array yang diindeks).sumber
Sudah ada banyak jawaban, tetapi inilah metode yang diandalkan Laravel dalam kelas Arr-nya:
Sumber: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
sumber
array_keys($keys)
akan mengembalikan array angka berurutan (0 ... X) yang memiliki panjang array yang sama. Sebagai contoharray_keys(["a", "b", "c"]) = [0, 1, 2];
array_keys([0, 1, 2]) = [0, 1, 2]
(karena array berurutan[0, 1, 2] !== [0, 1, 2]
). Contoh lain:array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];
array_keys(["a", "b", "c"]) = [0, 1, 2]
(karena array asosiatif["a", "b", "c"] !== [0, 1, 2]
). Semoga ini jelas (sulit dijelaskan secara luas dalam komentar, setidaknya untuk saya)Cepat, ringkas, dan efisien memori. Tidak ada perbandingan mahal, panggilan fungsi atau penyalinan array.
sumber
Dengan menggunakan xarray ekstensi PHP
Anda dapat melakukannya dengan sangat cepat (sekitar 30+ kali lebih cepat di PHP 5.6):
Atau:
sumber
Saya tahu ini sedikit sia-sia menambahkan jawaban untuk antrian besar ini, tapi inilah solusi O (n) yang dapat dibaca yang tidak memerlukan duplikasi nilai apa pun:
Daripada memeriksa kunci untuk melihat apakah semuanya numerik, Anda beralih ke kunci yang akan ada untuk array numerik dan pastikan ada.
sumber
[1,2,null,4]
akan gagal, tetapi array yang benar. jadi saya telah menambahkan beberapa peningkatan di stackoverflow.com/a/25206156/501831 denganarray_key_exists
cek tambahan )isset()
adalah alat yang salah di sini karena itu akan mengembalikan false jika nilainya diatur tetapinull
, seperti yang ditunjukkan oleh @ lazycommit.Solusi saya:
array_merge
pada satu array akan mengindeks ulang semuainteger
kunci, tetapi tidak yang lain. Sebagai contoh:Jadi jika daftar (array non-asosiatif) dibuat
['a', 'b', 'c']
maka nilai dihapusunset($a[1])
kemudianarray_merge
dipanggil, daftar tersebut dimulai kembali mulai dari 0.sumber
O(n)
dalam memori tambahan yang digunakan (karena ia menciptakan banyak array baru dengan elemen sebanyak$array
), jawabannya tidak menjawab ambiguitas pertanyaan yang ditanyakan atau menjelaskan dengan tepat bagaimana mendefinisikan daftar / array non-asosiatif, dan bahkan jika tidak satu pun dari poin ini benar, tidak jelas apakah ini menambah nilai dibandingkan dengan jawaban lain yang sudah diposting.Setelah melakukan beberapa pembandingan lokal, debugging, pencarian compiler, profiling, dan menyalahgunakan 3v4l.org untuk membuat tolok ukur di lebih banyak versi (ya, saya mendapat peringatan untuk berhenti) dan membandingkan setiap variasi yang dapat saya temukan ...
Saya memberi Anda fungsi array asosiatif skenario kasus rata-rata terbaik terburuk yang diturunkan secara organik yang paling buruk kira-kira sama baiknya atau lebih baik daripada semua skenario kasus rata-rata lainnya.
Dari https://3v4l.org/rkieX :
sumber
Inilah metode yang saya gunakan:
Perhatikan bahwa ini tidak memperhitungkan kasus khusus seperti:
Maaf, tidak dapat membantu Anda dengan itu. Ini juga agak berkinerja untuk array ukuran yang layak, karena tidak membuat salinan yang tidak perlu. Hal-hal kecil inilah yang membuat Python dan Ruby jauh lebih baik untuk dituliskan ...: P
sumber
Kedua contoh ini, yang mencetak poin terbanyak tidak bekerja dengan benar dengan susunan seperti
$array = array('foo' => 'bar', 1)
sumber
Ini juga akan berfungsi ( demo ):
Harap perhatikan bahwa poin utama dari jawaban ini adalah untuk memberi tahu Anda tentang keberadaan
SplFixedArray
dan tidak mendorong Anda untuk menggunakan Pengecualian untuk jenis tes ini.sumber
Saya pikir definisi skalar akan bervariasi berdasarkan aplikasi. Artinya, beberapa aplikasi akan memerlukan pengertian yang lebih ketat tentang apa yang memenuhi syarat sebagai skalar array, dan beberapa aplikasi akan membutuhkan pengertian yang lebih longgar.
Di bawah ini saya menyajikan 3 metode kekerasan yang bervariasi.
sumber
Satu lagi lebih cepat dari sumber . Cocok penyandian
json_encode
(danbson_encode
). Begitu juga kepatuhan javascript Array.sumber
isset
danarray_key_exists
? bukankah yang terakhir sudah cukup?isset()
cek di sini benar-benar berlebihan.isset()
lebih cepat dariarray_key_exists()
. lihat ilia.ws/archives/…null
s, tetapi juga tidak mungkin Anda memiliki array yang cukup besar sehingga akan ada perbedaan kinerja yang nyata dengan menggunakan kedua cekjson_encode
, Anda bisa memeriksa simbol pertama dari string, dikembalikan olehjson_encode($your_arr)
- apakah itu[
atau{
;-)Mungkinkah ini solusinya?
Peringatan jelas bahwa kursor array diatur ulang tetapi saya akan mengatakan mungkin fungsi ini digunakan sebelum array bahkan dilintasi atau digunakan.
sumber
array("a", "b")
danarray("a", "b" => "B")
karena hanya memeriksa kunci pertama. BTW,is_long
hanya aliasis_int
.[7 => 'foo', 2 => 'bar']
sebagai array "campuran" yang sebagian tetapi tidak berurutan "murni". Itu sepertinya penggunaan kata-kata yang jelas salah bagi saya.Banyak solusi di sini yang elegan dan cantik, tetapi tidak skala dengan baik, dan intensif memori atau intensif CPU. Sebagian besar membuat 2 titik data baru dalam memori dengan solusi ini dari kedua sisi perbandingan. Semakin besar susunan semakin sulit dan lebih lama proses dan memori yang digunakan, dan Anda kehilangan manfaat dari evaluasi hubung singkat. Saya melakukan beberapa pengujian dengan beberapa ide berbeda. Mencoba menghindari array_key_exists karena mahal, dan juga menghindari membuat dataset besar baru untuk dibandingkan. Saya merasa ini adalah cara sederhana untuk mengetahui apakah array berurutan.
Anda menjalankan hitungan tunggal pada array utama dan menyimpan integer tunggal. Anda kemudian loop melalui array dan memeriksa kecocokan tepat saat iterating the counter. Anda harus mulai dari 1 untuk menghitung. Jika gagal maka akan terjadi hubungan pendek yang memberi Anda peningkatan kinerja ketika itu salah.
Awalnya saya melakukan ini dengan for loop dan memeriksa isset ($ arr [$ i]) tetapi ini tidak akan mendeteksi kunci null yang memerlukan array_key_exists, dan seperti yang kita tahu itu adalah fungsi terburuk untuk digunakan untuk kecepatan.
Terus-menerus memperbarui variabel melalui foreach untuk memeriksa bersama dengan iterator yang tidak pernah tumbuh melebihi ukuran integer, mari PHP gunakan itu dibangun dalam optimasi memori, caching dan pengumpulan sampah untuk membuat Anda menggunakan sumber daya yang sangat rendah.
Juga, saya akan berpendapat bahwa menggunakan array_keys di foreach adalah konyol ketika Anda dapat menjalankan $ key => $ value dan memeriksa kuncinya. Mengapa membuat titik data baru? Setelah Anda abstrak, kunci array Anda telah menghabiskan lebih banyak memori dengan segera.
sumber
jawaban sudah diberikan tetapi ada terlalu banyak informasi yang keliru tentang kinerja. Saya menulis skrip benchmark kecil ini yang menunjukkan bahwa metode foreach adalah yang tercepat.
Penafian: metode berikut disalin dari jawaban lain
hasil:
sumber
Atau Anda bisa menggunakan ini:
yang akan memeriksa apakah array berisi kunci non-numerik atau:
untuk memeriksa apakah array benar-benar berurutan (berisi kunci int yang dibuat secara otomatis 0 hingga n-1 )
menggunakan perpustakaan ini .
sumber
Kecuali PHP memiliki builtin untuk itu, Anda tidak akan dapat melakukannya dalam waktu kurang dari O (n) - menghitung semua kunci dan memeriksa tipe integer. Bahkan, Anda juga ingin memastikan tidak ada lubang, sehingga algoritme Anda mungkin terlihat seperti:
Tapi kenapa repot-repot? Anggap saja array adalah tipe yang Anda harapkan. Jika tidak, itu hanya akan meledak di wajah Anda - itu pemrograman dinamis untuk Anda! Uji kode Anda dan semuanya akan baik-baik saja ...
sumber
Saya membandingkan perbedaan antara kunci-kunci array dan kunci-kunci hasil array_values () dari array, yang akan selalu berupa array dengan indeks integer. Jika kunci sama, itu bukan array asosiatif.
sumber
O(n)
memori tambahan ketika$array
memilikin
item, dan menulis(someboolean) ? false : true
bukannya!someboolean
mengerikan dan verbose.