Bagaimana cara memeriksa apakah array PHP asosiatif atau berurutan?

781

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');
Wilco
sumber
382
Ada bug dalam kode Anda: Tomat adalah buah.
Olle Härstedt
9
Metode ini memiliki peringatan, tetapi seringkali saya hanya melakukannya 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).
Gras Double
@ OlleHärstedt Tidak menurut Pengadilan Tinggi AS. ;-)
MC Emperor

Jawaban:

622

Anda telah mengajukan dua pertanyaan yang tidak cukup setara:

  • Pertama, cara menentukan apakah array hanya memiliki kunci numerik
  • Kedua, bagaimana menentukan apakah array memiliki kunci numerik berurutan , mulai dari 0

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:

function isAssoc(array $arr)
{
    if (array() === $arr) return false;
    return array_keys($arr) !== range(0, count($arr) - 1);
}

var_dump(isAssoc(['a', 'b', 'c'])); // false
var_dump(isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); // false
var_dump(isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); // true
var_dump(isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); // true
Mark Amery
sumber
32
Solusi yang sangat elegan. Perhatikan bahwa ia mengembalikan TRUE dalam kasus (ambigu) array kosong.
Jonathan Lidbeck
30
Saya pikir lebih berguna untuk memikirkan array berurutan sebagai kasus khusus array asosiatif. Jadi setiap array asosiatif, tetapi hanya beberapa yang berurutan. Oleh karena itu, suatu fungsi isSequential()akan lebih masuk akal daripada isAssoc(). Dalam fungsi seperti itu, array kosong harus dilihat sebagai berurutan. Rumusnya bisa array() === $arr || !isAssoc($arr).
donquixote
18
Saya pikir ini akan menghindari banyak waktu dan memori cpu potensial jika seseorang akan memeriksa apakah isset ($ arr [0]) salah sebelum mengekstraksi semua kunci seperti itu jelas asosiatif jika array tidak kosong tetapi tidak memiliki elemen dalam 0 posisi. Karena "kebanyakan" array asosiatif nyata memiliki string sebagai kunci, ini harus menjadi optimasi yang bagus untuk kasus umum fungsi tersebut.
OderWat
10
@OderWat - Optimasi Anda harus digunakan array_key_existsalih-alih issetkarena jika elemen nol adalah nilai nol, penerbit akan mengembalikan false salah. Nilai nol biasanya harus menjadi nilai yang sah dalam array tersebut.
OCDev
@ Maghitgarha, suntingan Anda mengubah perilaku fungsi tanpa penjelasan mengapa, dan membuatnya bertentangan dengan deskripsi dalam prosa di atas apa yang seharusnya dilakukan. Saya telah mengembalikannya.
Mark Amery
431

Untuk sekadar memeriksa apakah array memiliki kunci non-integer (bukan apakah array diindeks secara berurutan atau diindeks nol):

function has_string_keys(array $array) {
  return count(array_filter(array_keys($array), 'is_string')) > 0;
}

Jika setidaknya ada satu kunci string, $arrayakan dianggap sebagai array asosiatif.

Kapten kurO
sumber
22
Metode ini jauh lebih baik daripada yang terlihat. Jika count (filtered_array) == count (original_array), maka itu adalah array assoc. Jika hitung (filtered_array) == 0, maka itu adalah array yang diindeks. Jika count (filtered_array) <count (original_array), maka array memiliki kunci numerik dan string.
Jamol
5
@MikePretzlaw tentu saja iterates; tidak ada (mungkin) cara yang mungkin untuk menentukan apakah semua kunci array adalah ints tanpa melihat semua kunci dalam array. Saya berasumsi alternatif non-iterasi yang seharusnya kita lihat di bawah ini adalah yang seperti $isIndexed = array_values($arr) === $arr;? Yang saya tanyakan: bagaimana menurut Anda array_values()berfungsi? Bagaimana menurut Anda ===diterapkan pada array bekerja? Jawabannya tentu saja mereka juga beralih ke array.
Mark Amery
4
@ ARW "PHP sepertinya akan membuang semuanya ke int dalam definisi array jika bisa." - ya, itulah yang terjadi. WTF terbesar adalah bahwa ia melakukan ini untuk mengapung; jika Anda mencoba, 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.
Mark Amery
30
@MarkAmery Di atas, meskipun sederhana, menjamin 100% berjalan dari array. Akan lebih efisien, terutama jika Anda berurusan dengan array besar, jika Anda memeriksa string atau int dan pecah pada yang pertama kali Anda temukan. Misalnya: function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
Pemikiran
1
@Pikir Kode Anda bekerja sangat cepat tetapi tidak dapat mendeteksi array berurutan . Contoh array(1 => 'a', 0 => 'b', 2 => 'c')akan menjadi false(array berurutan) sedangkan seharusnya true(array asosiatif). toolsqa.com/data-structures/array-in-programming Saya tidak yakin apakah kuncinya harus naik urutan? (0, 1, ...)
vee
132

Tentunya ini adalah alternatif yang lebih baik.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
Dave Marshall
sumber
52
Ini akan menduplikasi nilai dalam array, yang berpotensi sangat mahal. Anda jauh lebih baik memeriksa kunci array.
meagar
8
Saya baru saja menggunakan ==; Saya tidak berpikir ada kebutuhan untuk === di sini. Tetapi untuk menjawab "tidak disetel dan tidak berfungsi": setelah Anda menghapus elemen pertama, itu bukan lagi array berindeks integer mulai dari 0. Jadi IMO berfungsi.
Grantwparks
4
Setuju dengan @grantwparks: Array jarang tidak diindeks. Menariknya karena tidak ada cara untuk benar-benar menghapus elemen dari tengah array yang diindeks PHP pada dasarnya menyatakan semua array sebagai asosiatif dan numerik hanyalah versi 'make the key for me'.
RickMeasham
7
Satu-satunya masalah yang saya miliki dengan ini adalah bahwa ===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.
Jesse
5
Catatan tambahan, ini gagal pada array yang ditentukan dengan kunci numerik yang rusak. mis. $ myArr = array (0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3'); Salah satu potensi penyelesaian adalah menjalankan ksort ($ arr) sebelum melakukan tes
Scott
77

Banyak komentator dalam pertanyaan ini tidak mengerti bagaimana array bekerja di PHP. Dari dokumentasi array :

Kunci dapat berupa bilangan bulat atau string. Jika kunci adalah representasi standar integer, itu akan ditafsirkan seperti itu (yaitu "8" akan ditafsirkan sebagai 8, sedangkan "08" akan ditafsirkan sebagai "08"). Kunci mengambang di terpotong ke bilangan bulat. Tipe array yang diindeks dan asosiatif adalah tipe yang sama dalam PHP, yang keduanya dapat berisi indeks integer dan string.

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):

function keyedNext( &$arr, &$k){
    $k = key($arr);
    return next($arr);
}

for ($k = key(reset($my_array)); is_int($k); keyedNext($my_array,$k))
    $onlyIntKeys = is_null($k);

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 "").

tupai
sumber
Ini tidak berfungsi untuk kunci integer non-sekuensial. Cobalah dengan [2 => 'a', 4 => 'b'].
DavidJ
2
@ DavidJ, Apa yang Anda maksud dengan "tidak bekerja"? Itu berhasil menentukan bahwa semua kunci adalah bilangan bulat. Apakah Anda mengklaim bahwa array seperti yang Anda posting tidak boleh dianggap sebagai "array numerik"?
coredumperror
7
Array non-asosiatif harus memiliki kunci mulai dari 0hingga count($array)-1, dalam urutan yang ketat ini. Pemeriksaan pendahuluan dengan is_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.
ofavre
2
Menggunakan foreachalih-alih iterasi eksplisit sekitar dua kali lebih cepat.
ofavre
1
Jika Anda ingin menjadikan ini sebagai fungsi: function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
GreeKatrina
39

Sebagaimana dinyatakan oleh OP :

PHP memperlakukan semua array sebagai asosiatif

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 ?:

The key baik dapat menjadi bilangan bulat atau tali .

Itu berarti ada 3 kemungkinan kasus:

  • Kasus 1. semua kunci adalah angka / bilangan bulat .
  • Kasus 2. semua kunci string .
  • Kasus 3. beberapa kunci adalah string , beberapa kunci adalah numerik / bilangan bulat .

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.

//! Check whether the input is an array whose keys are all integers.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all integers.
*/
function IsArrayAllKeyInt($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_int", array_keys($InputArray))) === array(true);
}

Kasus 2: semua kunci adalah string .

Catatan : Fungsi ini mengembalikan true untuk array kosong juga.

//! Check whether the input is an array whose keys are all strings.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are all strings.
*/
function IsArrayAllKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_unique(array_map("is_string", array_keys($InputArray))) === array(true);
}

Kasus 3. beberapa kunci adalah string , beberapa kunci adalah numerik / bilangan bulat .

Catatan : Fungsi ini mengembalikan true untuk array kosong juga.

//! Check whether the input is an array with at least one key being an integer and at least one key being a string.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array with at least one key being an integer and at least one key being a string.
*/
function IsArraySomeKeyIntAndSomeKeyString($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return count(array_unique(array_map("is_string", array_keys($InputArray)))) >= 2;
}

Oleh karena itu:


Sekarang, untuk sebuah array menjadi array "asli" yang kita semua terbiasa, artinya:

  • Kuncinya semua numerik / bilangan bulat .
  • Kuncinya berurutan (yaitu meningkat pada langkah 1).
  • Kuncinya mulai dari nol .

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.

//! Check whether the input is an array whose keys are numeric, sequential, and zero-based.
/*!
    \param[in] $InputArray          (array) Input array.
    \return                         (bool) \b true iff the input is an array whose keys are numeric, sequential, and zero-based.
*/
function IsArrayKeyNumericSequentialZeroBased($InputArray)
{
    if(!is_array($InputArray))
    {
        return false;
    }

    if(count($InputArray) <= 0)
    {
        return true;
    }

    return array_keys($InputArray) === range(0, count($InputArray) - 1);
}

Peringatan / Kesalahan (atau, fakta lebih aneh tentang kunci array di PHP)

Kunci integer

Kunci untuk array ini adalah bilangan bulat :

array(0 => "b");
array(13 => "b");
array(-13 => "b");          // Negative integers are also integers.
array(0x1A => "b");         // Hexadecimal notation.

Kunci dawai

Kunci untuk array ini adalah string :

array("fish and chips" => "b");
array("" => "b");                                   // An empty string is also a string.
array("[email protected]" => "b");    // Strings may contain non-alphanumeric characters.
array("stack\t\"over\"\r\nflow's cool" => "b");     // Strings may contain special characters.
array('$tα€k↔øv∈rflöw⛄' => "b");                    // Strings may contain all kinds of symbols.
array("functіon" => "b");                           // You think this looks fine? Think again! (see https://stackoverflow.com/q/9246051/1402846)
array("ま말轉转ДŁ" => "b");                         // How about Japanese/Korean/Chinese/Russian/Polish?
array("fi\x0sh" => "b");                            // Strings may contain null characters.
array(file_get_contents("https://www.google.com/images/nav_logo114.png") => "b");   // Strings may even be binary!

Kunci integer yang terlihat seperti string

Jika Anda pikir kunci dalam array("13" => "b")adalah string , Anda salah . Dari dokumen di sini :

String yang berisi bilangan bulat yang valid akan dilemparkan ke tipe bilangan bulat. Misalnya kunci "8" sebenarnya akan disimpan di bawah 8. Di sisi lain "08" tidak akan dilemparkan, karena itu bukan bilangan bulat desimal yang valid.

Misalnya, kunci untuk array ini adalah bilangan bulat :

array("13" => "b");
array("-13" => "b");                        // Negative, ok.

Tetapi kunci untuk array ini adalah string :

array("13." => "b");
array("+13" => "b");                        // Positive, not ok.
array("-013" => "b");
array("0x1A" => "b");                       // Not converted to integers even though it's a valid hexadecimal number.
array("013" => "b");                        // Not converted to integers even though it's a valid octal number.
array("18446744073709551616" => "b");       // Not converted to integers as it can't fit into a 64-bit integer.

Terlebih lagi, menurut dokter ,

Ukuran integer tergantung pada platform, meskipun nilai maksimum sekitar dua miliar adalah nilai biasa (yang 32 bit ditandatangani). Platform 64-bit biasanya memiliki nilai maksimum sekitar 9E18, kecuali untuk Windows, yang selalu 32 bit. PHP tidak mendukung bilangan bulat yang tidak ditandatangani.

Jadi kunci untuk array ini mungkin atau tidak mungkin menjadi bilangan bulat - itu tergantung pada platform Anda.

array("60000000000" => "b");                // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.

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"))berikan

array(1) {
    [2147483647]=>
    string(1) "b"
}   

tetapi pada demo langsung ini pada codepad (PHP 5.2.5), ekspresi yang sama memberikan

array(1) {
    ["2147483647"]=>
    string(1) "b"
}

Jadi kuncinya adalah integer di satu lingkungan tetapi string di yang lain, meskipun 2147483647adalah 32-bit yang ditandatangani integer .

Pang
sumber
2
Kecuali, seperti yang saya sebutkan di bawah, ini melibatkan pembuatan duplikat array ke yang sedang diperiksa, membuatnya sangat mahal untuk array besar, dan sumber potensial kehabisan memori crash pada host bersama.
podperson
35

Dari segi kecepatan:

function isAssoc($array)
{
    return ($array !== array_values($array));
}

Memori-bijaksana:

function isAssoc($array)
{
    $array = array_keys($array); return ($array !== array_keys($array));
}
Alix Axel
sumber
array berikut: array (02 => 11,1,2,456); ditampilkan sebagai tidak memiliki kunci numerik menggunakan algoritma di atas, bahkan jika 02 === 2
Galileo_Galilei
20
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}
dsims
sumber
2
Ini adalah satu - satunya jawaban (pada saat komentar saya) yang dapat menangani yang berikut: $ array = array (0 => 'blah', 2 => 'yep', 3 => 'wahey')
Shabbyrobe
tetapi array('1'=>'asdf', '2'=>'too')akan dianggap sebagai array asosiatif sementara sebenarnya tidak (kunci sebenarnya string)
Kapten kurO
1
@ KaptenkurO Maksudmu numerik. Ini adalah array asosiatif.
devios1
1
Fungsi ini kembali truejika tombolnya adalah: nol, bilangan bulat (hanya positif), string kosong, atau kombinasi apa pun di atas, seperti string "09". Fungsi ini tidak memperhitungkan urutan tombol. Jadi array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey')dan array('blah', 'yep', 'wahey')semuanya asosiatif menurut fungsi ini, sementara array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')tidak.
Pang
@CaptainkurO Anda salah. '1' dan '2' akan disimpan sebagai bilangan bulat. Baca bagian kutipan jawaban tupai dari 11 Mei 2011 pukul 19:34. PHP tidak menyimpan kunci string yang terlihat persis seperti bilangan bulat. Itu mengkonversi mereka menjadi bilangan bulat.
Buttle Butkus
20

Sebenarnya cara yang paling efisien adalah sebagai berikut:

function is_assoc($array){
   $keys = array_keys($array);
   return $keys !== array_keys($keys);
}

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).

anon
sumber
1
Pintar, tapi tidak bagus. Mengapa ini "paling efisien"? Akan jauh lebih mudah dibaca untuk hanya membandingkan array_keys ($ a) dengan rentang (0, hitung ($ a)). Solusi paling cerdas jarang yang terbaik dalam pengalaman saya. Terutama ketika menjadi pintar menambah secara harfiah tidak ada nilai lebih dari alternatif yang jelas dan bersih.
Shane H
4
Fungsi ini mengembalikan trueuntuk array(1=>"a")tetapi falseuntuk array("a"=>"a"). Akan lebih bermakna jika !=digantikan oleh !==.
Pang
1
@Pang kamu benar. Saya pikir komentar Anda pasti salah pada awalnya, tetapi, yang mengejutkan saya, [0] == ['a']di PHP (sejak 0 == 'a', dan, memang, 0 == 'banana'). Operator PHP ==gila.
Mark Amery
2
Ini tidak efisien sejauh ini melibatkan memanggil array_keys vs hanya memeriksa sampai Anda menemukan indeks integer non-sekuensial. Di bawah tenda Anda tetap melakukan itu , tetapi Anda sudah menduplikasi array besar.
podperson
17

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_keysdan array_valueskeduanya 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:

function array_type( $obj ){
    $last_key = -1;
    $type = 'index';
    foreach( $obj as $key => $val ){
        if( !is_int( $key ) || $key < 0 ){
            return 'assoc';
        }
        if( $key !== $last_key + 1 ){
            $type = 'sparse';
        }
        $last_key = $key;
    }
    return $type;
}

Perhatikan juga bahwa jika Anda tidak ingin membedakan array jarang dari array asosiatif, Anda cukup kembali 'assoc'dari kedua ifblok.

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.

podperson
sumber
13

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:

function is_indexed_array(&$arr) {
  for (reset($arr); is_int(key($arr)); next($arr));
  return is_null(key($arr));
}

function is_sequential_array(&$arr, $base = 0) {
  for (reset($arr), $base = (int) $base; key($arr) === $base++; next($arr));
  return is_null(key($arr));
}

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:

  • Memori bijaksana: Tidak menyalin data atau rentang kunci. Melakukan array_values ​​atau array_keys mungkin tampak lebih pendek (kode kurang) tetapi perlu diingat apa yang terjadi di latar belakang setelah Anda melakukan panggilan itu. Ya, ada lebih banyak pernyataan (terlihat) daripada di beberapa solusi lain, tetapi bukan itu yang diperhitungkan, bukan?
  • Dari segi waktu: Selain fakta bahwa menyalin / mengekstraksi data dan / atau kunci juga membutuhkan waktu, solusi ini lebih efisien daripada melakukan foreach. Sekali lagi foreach mungkin tampak lebih efisien untuk beberapa karena lebih pendek dalam notasi, tetapi di latar belakang foreach juga panggilan reset, kunci dan selanjutnya melakukannya perulangan. Tetapi selain itu juga panggilan valid untuk memeriksa kondisi akhir, yang dihindari di sini karena kombinasi dengan cek integer.

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.

Niels Ockeloen
sumber
1
Ini jawaban terbaik. Definisi array "asosiatif" atau "numerik" tergantung pada situasi spesifik.
Pato
Jika foreach kurang efisien daripada metode yang digunakan di sini maka, selain dari ketidaknyamanan menggunakan dua fungsi yang berbeda, kinerja solusi ini lebih baik daripada milikku (pendahulunya). Saya kira tidak, karena foreach direkomendasikan sebagai cara tercepat untuk melalui array.
podperson
7

Fungsi ini dapat menangani:

  • array dengan lubang dalam indeks (mis. 1,2,4,5,8,10)
  • array dengan kunci "0x": mis. kunci '08' adalah asosiatif sedangkan kunci '8' berurutan.

idenya sederhana: jika salah satu kunci BUKAN bilangan bulat, itu adalah array asosiatif, jika tidak itu berurutan.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
LazNiko
sumber
1
"Jika salah satu kunci BUKAN bilangan bulat, itu adalah array asosiatif, jika tidak berurutan" - ya? Tidak, ini salah. Ada ruang untuk argumen tentang apa yang merupakan array "asosiatif", tetapi makna "sekuensial" cukup jelas, dan itu tidak sama dengan semua kunci menjadi angka.
Mark Amery
Jika salah satu kunci BUKAN bilangan bulat itu IS asosiatif pada dasarnya, bagaimanapun, itu hanya berurutan jika kunci pergi dari 0 - panjang (array) - 1. Namun NUMERIK, jika semua kunci hanya diberi nomor, tetapi mungkin atau mungkin tidak berfungsi dengan banyak fungsi array yang memerlukan array berurutan. Jika Anda mengubah array numerik dengan lubang menjadi berurutan dengan menjalankan array_values ​​(array) di atasnya, maka itu akan dikonversi menjadi berurutan.
geilt
7

Saya memperhatikan dua pendekatan populer untuk pertanyaan ini: satu menggunakan array_values()dan lainnya menggunakan key(). Untuk mengetahui mana yang lebih cepat, saya menulis sebuah program kecil:

$arrays = Array(
  'Array #1' => Array(1, 2, 3, 54, 23, 212, 123, 1, 1),
  'Array #2' => Array("Stack", 1.5, 20, Array(3.4)),
  'Array #3' => Array(1 => 4, 2 => 2),
  'Array #4' => Array(3.0, "2", 3000, "Stack", 5 => "4"),
  'Array #5' => Array("3" => 4, "2" => 2),
  'Array #6' => Array("0" => "One", 1.0 => "Two", 2 => "Three"),
  'Array #7' => Array(3 => "asdf", 4 => "asdf"),
  'Array #8' => Array("apple" => 1, "orange" => 2),
);

function is_indexed_array_1(Array &$arr) {
  return $arr === array_values($arr);
}

function is_indexed_array_2(Array &$arr) {
  for (reset($arr), $i = 0; key($arr) === $i++; next($arr))
    ;
  return is_null(key($arr));
}

// Method #1
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_1($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

// Method #2
$start = microtime(true);
for ($i = 0; $i < 1000; $i++) {
  foreach ($arrays as $array) {
    $dummy = is_indexed_array_2($array);
  }
}
$end = microtime(true);
echo "Time taken with method #1 = ".round(($end-$start)*1000.0,3)."ms\n";

Output untuk program pada PHP 5.2 di CentOS adalah sebagai berikut:

Waktu yang diambil dengan metode # 1 = 10.745 ms
Waktu yang diambil dengan metode # 2 = 18.239 ms

Output pada PHP 5.3 menghasilkan hasil yang serupa. Jelas menggunakan array_values()jauh lebih cepat.

Manu Manjunath
sumber
tolok ukur yang buruk. Anda tidak menguji untuk array besar. Di komputer saya mulai 10K + elemen metode # 2 lebih cepat. Coba dengan$arrays = Array( 'Array #1' => range(0, 50000), );
nonsensei
7

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).

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
MAChitgarha
sumber
Ksort () tidak perlu menurut saya. Solusi ini berfungsi tetapi harus menguji apakah $ arr bernilai nol dan jika json_encode gagal, maka cobalah / tangkap. + Tidak benar-benar optimal jika $ arr besar.
lucbonnin
7

Sudah ada banyak jawaban, tetapi inilah metode yang diandalkan Laravel dalam kelas Arr-nya:

/**
 * Determines if an array is associative.
 *
 * An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
 *
 * @param  array  $array
 * @return bool
 */
public static function isAssoc(array $array)
{
    $keys = array_keys($array);

    return array_keys($keys) !== $keys;
}

Sumber: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

Ben
sumber
1
@Casey array_keys($keys)akan mengembalikan array angka berurutan (0 ... X) yang memiliki panjang array yang sama. Sebagai contoh array_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)
valepu
Algoritma ini gila, mudah, dapat dimengerti.
Benyi
Ini tidak akan berfungsi jika Anda memiliki array berturut-turut dari baris asosiatif.
lucbonnin
5
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

Cepat, ringkas, dan efisien memori. Tidak ada perbandingan mahal, panggilan fungsi atau penyalinan array.

Jesse
sumber
4

Dengan menggunakan xarray ekstensi PHP

Anda dapat melakukannya dengan sangat cepat (sekitar 30+ kali lebih cepat di PHP 5.6):

if (array_is_indexed($array)) {  }

Atau:

if (array_is_assoc($array)) {  }
c9s
sumber
3

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:

function isNumericArray($array) {
    $count = count($array);
    for ($i = 0; $i < $count; $i++) {
        if (!isset($array[$i])) {
            return FALSE;
        }
    }
    return TRUE;
}

Daripada memeriksa kunci untuk melihat apakah semuanya numerik, Anda beralih ke kunci yang akan ada untuk array numerik dan pastikan ada.

cloudfeet
sumber
satu poin lagi. array dalam bentuk [1,2,null,4]akan gagal, tetapi array yang benar. jadi saya telah menambahkan beberapa peningkatan di stackoverflow.com/a/25206156/501831 dengan array_key_existscek tambahan )
lazycommit
-1; isset()adalah alat yang salah di sini karena itu akan mengembalikan false jika nilainya diatur tetapi null, seperti yang ditunjukkan oleh @ lazycommit.
Mark Amery
3

Solusi saya:

function isAssociative(array $array)
{
    return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}

array_mergepada satu array akan mengindeks ulang semua integerkunci, tetapi tidak yang lain. Sebagai contoh:

array_merge([1 => 'One', 3 => 'Three', 'two' => 'Two', 6 => 'Six']);

// This will returns [0 => 'One', 1 => 'Three', 'two' => 'Two', 2 => 'Six']

Jadi jika daftar (array non-asosiatif) dibuat ['a', 'b', 'c']maka nilai dihapus unset($a[1])kemudian array_mergedipanggil, daftar tersebut dimulai kembali mulai dari 0.

ByScripts
sumber
-1; ini ada 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.
Mark Amery
3

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.

/**
 * Tests if an array is an associative array.
 *
 * @param array $array An array to test.
 * @return boolean True if the array is associative, otherwise false.
 */
function is_assoc(array &$arr) {
    // don't try to check non-arrays or empty arrays
    if (FALSE === is_array($arr) || 0 === ($l = count($arr))) {
        return false;
    }

    // shortcut by guessing at the beginning
    reset($arr);
    if (key($arr) !== 0) {
        return true;
    }

    // shortcut by guessing at the end
    end($arr);
    if (key($arr) !== $l-1) {
        return true;
    }

    // rely on php to optimize test by reference or fast compare
    return array_values($arr) !== $arr;
}

Dari https://3v4l.org/rkieX :

<?php

// array_values
function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

// method_2 was DQ; did not actually work

// array_keys
function method_3(Array &$arr) {
    return array_keys($arr) === range(0, count($arr) - 1);
}

// foreach
function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        ++$idx;
    }
    return TRUE;
}

// guessing
function method_5(Array &$arr) {
    global $METHOD_5_KEY;
    $i = 0;
    $l = count($arr)-1;

    end($arr);
    if ( key($arr) !== $l )
        return FALSE;

    reset($arr);
    do {
        if ( $i !== key($arr) )
            return FALSE;
        ++$i;
        next($arr);
    } while ($i < $l);
    return TRUE;
}

// naieve
function method_6(Array &$arr) {
    $i = 0;
    $l = count($arr);
    do {
        if ( NULL === @$arr[$i] )
            return FALSE;
        ++$i;
    } while ($i < $l);
    return TRUE;
}

// deep reference reliance
function method_7(Array &$arr) {
    return array_keys(array_values($arr)) === array_keys($arr);
}


// organic (guessing + array_values)
function method_8(Array &$arr) {
    reset($arr);
    if ( key($arr) !== 0 )
        return FALSE;

    end($arr);
    if ( key($arr) !== count($arr)-1 )
        return FALSE;

    return array_values($arr) === $arr;
}

function benchmark(Array &$methods, Array &$target, $expected){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 2000; ++$i) {
            //$dummy = call_user_func($method, $target);
            if ( $method($target) !== $expected ) {
                echo "Method $method is disqualified for returning an incorrect result.\n";
                unset($methods[array_search($method,$methods,true)]);
                $i = 0;
                break;
            }
        }
        if ( $i != 0 ) {
            $end = microtime(true);
            echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
        }
    }
}



$true_targets = [
    'Giant array' => range(0, 500),
    'Tiny array' => range(0, 20),
];


$g = range(0,10);
unset($g[0]);

$false_targets = [
    'Large array 1' => range(0, 100) + ['a'=>'a'] + range(101, 200),
    'Large array 2' => ['a'=>'a'] + range(0, 200),
    'Tiny array' => range(0, 10) + ['a'=>'a'] + range(11, 20),
    'Gotcha array' => $g,
];

$methods = [
    'method_1',
    'method_3',
    'method_4',
    'method_5',
    'method_6',
    'method_7',
    'method_8'
];


foreach($false_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecing FALSE ====\n";
    benchmark($methods, $target, false);
    echo "\n";
}
foreach($true_targets as $targetName => $target){
    echo "==== Benchmark using $targetName expecting TRUE ====\n";
    benchmark($methods, $target, true);
    echo "\n";
}
TylerY86
sumber
2

Inilah metode yang saya gunakan:

function is_associative ( $a )
{
    return in_array(false, array_map('is_numeric', array_keys($a)));
}

assert( true === is_associative(array(1, 2, 3, 4)) );

assert( false === is_associative(array('foo' => 'bar', 'bar' => 'baz')) );

assert( false === is_associative(array(1, 2, 3, 'foo' => 'bar')) );

Perhatikan bahwa ini tidak memperhitungkan kasus khusus seperti:

$a = array( 1, 2, 3, 4 );

unset($a[1]);

assert( true === is_associative($a) );

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

AL X
sumber
2
<?php

function is_list($array) {
    return array_keys($array) === range(0, count($array) - 1);
}

function is_assoc($array) {
    return count(array_filter(array_keys($array), 'is_string')) == count($array);
}

?>

Kedua contoh ini, yang mencetak poin terbanyak tidak bekerja dengan benar dengan susunan seperti $array = array('foo' => 'bar', 1)

KillEveryBody
sumber
+1 Is_list Anda () adalah IMO jawaban terbaik. Beberapa orang tidak memiliki petunjuk tentang kompleksitas ruang & waktu, dan fungsi skrip asli vs PHP ...
e2-e4
2

Ini juga akan berfungsi ( demo ):

function array_has_numeric_keys_only(array $array)
{
    try {
        SplFixedArray::fromArray($array, true);
    } catch (InvalidArgumentException $e) {
        return false;
    }
    return true;
}

Harap perhatikan bahwa poin utama dari jawaban ini adalah untuk memberi tahu Anda tentang keberadaan SplFixedArraydan tidak mendorong Anda untuk menggunakan Pengecualian untuk jenis tes ini.

Gordon
sumber
2

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.

<?php
/**
 * Since PHP stores all arrays as associative internally, there is no proper
 * definition of a scalar array.
 * 
 * As such, developers are likely to have varying definitions of scalar array,
 * based on their application needs.
 * 
 * In this file, I present 3 increasingly strict methods of determining if an
 * array is scalar.
 * 
 * @author David Farrell <[email protected]>
 */

/**
 * isArrayWithOnlyIntKeys defines a scalar array as containing
 * only integer keys.
 * 
 * If you are explicitly setting integer keys on an array, you
 * may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    foreach ($a as $k => $v)
        if (!is_int($k))
            return false;
    return true;
}

/**
 * isArrayWithOnlyAscendingIntKeys defines a scalar array as
 * containing only integer keys in ascending (but not necessarily
 * sequential) order.
 * 
 * If you are performing pushes, pops, and unsets on your array,
 * you may need this function to determine scalar-ness.
 * 
 * @param array $a
 * @return boolean
 */ 
function isArrayWithOnlyAscendingIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $prev = null;
    foreach ($a as $k => $v)
    {
        if (!is_int($k) || (null !== $prev && $k <= $prev))
            return false;
        $prev = $k;
    }
    return true;
}

/**
 * isArrayWithOnlyZeroBasedSequentialIntKeys defines a scalar array
 * as containing only integer keys in sequential, ascending order,
 * starting from 0.
 * 
 * If you are only performing operations on your array that are
 * guaranteed to either maintain consistent key values, or that
 * re-base the keys for consistency, then you can use this function.
 * 
 * @param array $a
 * @return boolean
 */
function isArrayWithOnlyZeroBasedSequentialIntKeys(array $a)
{
    if (!is_array($a))
        return false;
    $i = 0;
    foreach ($a as $k => $v)
        if ($i++ !== $k)
            return false;
    return true;
}
David Farrell
sumber
2

Satu lagi lebih cepat dari sumber . Cocok penyandian json_encode(dan bson_encode). Begitu juga kepatuhan javascript Array.

function isSequential($value){
    if(is_array($value) || ($value instanceof \Countable && $value instanceof \ArrayAccess)){
        for ($i = count($value) - 1; $i >= 0; $i--) {
            if (!isset($value[$i]) && !array_key_exists($i, $value)) {
                return false;
            }
        }
        return true;
    } else {
        throw new \InvalidArgumentException(
            sprintf('Data type "%s" is not supported by method %s', gettype($value), __METHOD__)
        );
    }
}
lazycommit
sumber
1
Mengapa issetdan array_key_exists? bukankah yang terakhir sudah cukup?
mcfedr
@ mcfedr ya, itu akan - isset()cek di sini benar-benar berlebihan.
Mark Amery
@ mcfedr, @ mark-amery karena alasan kinerja. isset()lebih cepat dari array_key_exists(). lihat ilia.ws/archives/…
lazycommit
@ lazycommit Ini akan tergantung pada array Anda kemudian pada apakah lebih baik dengan atau tanpa, bukan karena cenderung memiliki array dengan banyak nulls, tetapi juga tidak mungkin Anda memiliki array yang cukup besar sehingga akan ada perbedaan kinerja yang nyata dengan menggunakan kedua cek
mcfedr
2
Jika Anda perlu memeriksa apakah itu cocok json_encode, Anda bisa memeriksa simbol pertama dari string, dikembalikan oleh json_encode($your_arr)- apakah itu [atau {;-)
pilat
2

Mungkinkah ini solusinya?

  public static function isArrayAssociative(array $array) {
      reset($array);
      return !is_int(key($array));
  }

Peringatan jelas bahwa kursor array diatur ulang tetapi saya akan mengatakan mungkin fungsi ini digunakan sebelum array bahkan dilintasi atau digunakan.

Kat Lim Ruiz
sumber
Fungsi ini mengembalikan false untuk keduanya array("a", "b")dan array("a", "b" => "B")karena hanya memeriksa kunci pertama. BTW, is_longhanya aliasis_int .
Pang
1
sejujurnya saya pikir ini akan sangat efektif dalam sebagian besar kasus, dan jauh lebih efisien daripada alternatifnya. Jika Anda memahami konsekuensi dari metode ini, dan menyadari bahwa itu akan berhasil untuk Anda, kemungkinan itu adalah pilihan terbaik.
Gershom
Ini salah; itu hanya terlihat pada tombol pertama.
Mark Amery
@MarkAmery pertanyaan bertanya bagaimana membedakan murni array berurutan dari murni array asosiatif. Jawaban ini tidak persis seperti itu dan merupakan yang paling efisien dari semuanya. Memiliki perilaku yang tidak terdefinisi untuk array campuran sangat baik dalam konteks pertanyaan. +1
Tobia
@Tobia Saya tidak berpikir kebanyakan orang akan setuju dengan Anda mengklasifikasikan, katakanlah, [7 => 'foo', 2 => 'bar']sebagai array "campuran" yang sebagian tetapi tidak berurutan "murni". Itu sepertinya penggunaan kata-kata yang jelas salah bagi saya.
Mark Amery
2

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.

public function is_sequential( $arr = [] ){
    if( !is_array( $arr ) || empty( $arr ) ) return false;

    $i = 0;

    $total = count( $arr );

    foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;

    return true;
}

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.

geilt
sumber
1

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

<?php

function method_1(Array &$arr) {
    return $arr === array_values($arr);
}

function method_2(Array &$arr) {
    for (reset($arr), $i = 0; key($arr) !== $i++; next($arr));
    return is_null(key($arr));
}

function method_3(Array &$arr) {
    return array_keys($arr) === range(0, count($arr) - 1);
}

function method_4(Array &$arr) {
    $idx = 0;
    foreach( $arr as $key => $val ){
        if( $key !== $idx )
            return FALSE;
        $idx++;
    }
    return TRUE;
}




function benchmark(Array $methods, Array &$target){    
    foreach($methods as $method){
        $start = microtime(true);
        for ($i = 0; $i < 1000; $i++)
            $dummy = call_user_func($method, $target);

        $end = microtime(true);
        echo "Time taken with $method = ".round(($end-$start)*1000.0,3)."ms\n";
    }
}



$targets = [
    'Huge array' => range(0, 30000),
    'Small array' => range(0, 1000),
];
$methods = [
    'method_1',
    'method_2',
    'method_3',
    'method_4',
];
foreach($targets as $targetName => $target){
    echo "==== Benchmark using $targetName ====\n";
    benchmark($methods, $target);
    echo "\n";
}

hasil:

==== Benchmark using Huge array ====
Time taken with method_1 = 5504.632ms
Time taken with method_2 = 4509.445ms
Time taken with method_3 = 8614.883ms
Time taken with method_4 = 2720.934ms

==== Benchmark using Small array ====
Time taken with method_1 = 77.159ms
Time taken with method_2 = 130.03ms
Time taken with method_3 = 160.866ms
Time taken with method_4 = 69.946ms
nonsensei
sumber
1

Atau Anda bisa menggunakan ini:

Arr::isAssoc($array)

yang akan memeriksa apakah array berisi kunci non-numerik atau:

Arr:isAssoc($array, true)

untuk memeriksa apakah array benar-benar berurutan (berisi kunci int yang dibuat secara otomatis 0 hingga n-1 )

menggunakan perpustakaan ini .

Pekerjaan kecil
sumber
0

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:

for i in 0 to len(your_array):
    if not defined(your-array[i]):
        # this is not an array array, it's an associative array :)

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 ...

Daren Thomas
sumber
1
Biasanya hanya dengan asumsi array adalah tipe yang diinginkan akan menjadi cara untuk pergi. Tetapi dalam kasus saya, saya mengulang melalui array multidimensi dan memformat output tergantung pada jenis array yang diberikan node.
Wilco
0

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.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}
philroy
sumber
-1; ini menggunakan O(n)memori tambahan ketika $arraymemiliki nitem, dan menulis (someboolean) ? false : truebukannya !somebooleanmengerikan dan verbose.
Mark Amery