PHP dizisinin ilişkisel veya ardışık olup olmadığı nasıl kontrol edilir?


781

PHP tüm dizileri birleştirici olarak ele alır, bu nedenle yerleşik işlevler yoktur. Herkes bir dizinin yalnızca sayısal anahtarlar içerip içermediğini kontrol etmek için oldukça verimli bir yol önerebilir mi?

Temel olarak, bu arasında ayrım yapabilmek istiyorum:

$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');

ve bu:

$assocArray = array('fruit1' => 'apple', 
                    'fruit2' => 'orange', 
                    'veg1' => 'tomato', 
                    'veg2' => 'carrot');

382
Kodunuzda bir hata var: Domates bir meyvedir.
Olle Härstedt

9
Bu yöntemin uyarıları vardır, ancak genellikle if (isset($array[0]))basit ve hızlı olanı yaparım . Tabii ki, önce dizinin boş olmadığından emin olmalısınız ve yöntemin başarısız olamaması için dizinin olası içeriği hakkında biraz bilginiz olmalıdır (karışık sayısal / çağrışımsal veya sıralı olmayan gibi).
Gras Double

@ OlleHärstedt ABD Yüksek Mahkemesi'ne göre değil . ;-)
MC İmparatoru

Yanıtlar:


622

Eşdeğer olmayan iki soru sordunuz:

  • İlk olarak, bir dizinin yalnızca sayısal anahtarları olup olmadığını belirleme
  • İkincisi, bir dizinin 0'dan başlayarak sıralı sayısal tuşlara sahip olup olmadığı nasıl belirlenir

Bu davranışlardan hangisine gerçekten ihtiyacınız olduğunu düşünün. (Ya sizin amaçlarınız için de olabilir.)

İlk soru (tüm tuşların sayısal olup olmadığını kontrol etmek) Kaptan kurO tarafından iyi cevaplanmıştır .

İkinci soru için (dizinin sıfır indeksli ve sıralı olup olmadığını kontrol ederek), aşağıdaki işlevi kullanabilirsiniz:

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

32
Çok zarif bir çözüm. Boş bir dizinin (belirsiz) durumunda TRUE değerini döndürdüğünü unutmayın.
Jonathan Lidbeck

30
Sıralı dizileri özel bir ilişkisel diziler olarak düşünmenin daha yararlı olduğunu düşünüyorum. Yani her dizi ilişkilendirilebilir, ancak sadece bazıları sıralıdır. Bu nedenle, bir işlev isSequential()daha anlamlı olur isAssoc(). Bu tür bir işlev olarak, boş bir dizi gereken sıralı olarak görülebilir. Formül olabilir array() === $arr || !isAssoc($arr).
donquixote

18
Ben bir dizi boş değilse ama 0 hiçbir öğe varsa açıkça ilişkilendirilebilir olduğu gibi tüm anahtarları çıkarmadan önce isset ($ arr [0]) yanlış olup olmadığını kontrol ederse, bu potansiyel cpu zaman ve bellek çok önleyeceğini düşünüyorum durum. "En" gerçek ilişkisel dizilerin anahtar olarak dizeleri olduğundan, bu tür bir işlevin genel durumu için hoş bir optimizasyon olmalıdır.
OderWat

10
@OderWat - Optimizasyonunuz kullanmalıdır array_key_existsyerine issetsıfır elemanı bir boş değer ise, isset hatalı return false çünkü. Bir null değer normalde böyle bir dizideki meşru bir değer olmalıdır.
OCDev

@MAChitgarha, düzenlemeniz, neden herhangi bir açıklama yapmadan işlevin davranışını değiştirdi ve gerçekte yapması gerekenin yukarıdaki nesirdeki açıklamayla çelişmesine neden oldu. Geri döndüm.
Mark Amery

431

Yalnızca dizinin tamsayı olmayan anahtarları olup olmadığını kontrol etmek için (dizinin sırayla dizine eklenmiş veya sıfır dizine alınmış olup olmadığını değil):

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

En az bir dize anahtarı varsa, $arrayilişkilendirilebilir bir dizi olarak kabul edilir.


22
Bu yöntem göründüğünden çok daha iyi. Count (filter_array) == count (original_array) ise, bir assoc dizisidir. Count (filter_array) == 0 ise, dizinlenmiş bir dizidir. Count (filter_array) <count (original_array) ise, dizi hem sayısal hem de dize tuşlarına sahiptir.
Jamol

5
@MikePretzlaw elbette yineliyor ; dizideki tüm anahtarların dizideki tüm anahtarlara bakmadan ints olup olmadığını belirlemenin olası bir yolu yoktur. Sanırım aşağıda görmemiz gereken yinelemesiz alternatifler şöyle $isIndexed = array_values($arr) === $arr;? Hangisine soruyorum: sizce nasıl array_values()çalışır? Dizilere nasıl ===uygulanacağını düşünüyorsunuz ? Cevap tabii ki dizi üzerinde de yinelemeleri.
Mark Amery

4
@ARW "PHP bir dizi tanımındaki her şeyi bir int'e döküyor gibi görünüyor." - evet, tam olarak böyle oluyor. En büyük WTF bunu yüzmek için bile yapıyor; denerseniz var_dump([1.2 => 'foo', 1.5 => 'bar']);diziyi aldığınızı keşfedeceksiniz [1 => 'bar']. Bir anahtarın orijinal türünü bulmanın hiçbir yolu yoktur. Evet, bütün bunlar korkunç; PHP'nin dizileri dilin en kötü kısmıdır ve hasarın çoğu telafi edilemez ve geleneksel diziler için tek bir yapı kullanma ve geleneksel hashmaps'ın en başından beri korkunç olması fikrine borçludur.
Mark Amery

30
@MarkAmery Yukarıdaki basit olsa da, dizinin% 100 yürüyüşünü garanti eder. Özellikle büyük dizilerle uğraşıyorsanız, dize veya int için kontrol ediyor ve ilk bulduğunuzda patlamış olsaydınız daha verimli olurdu. Örneğin: function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
Düşünce

1
@Thought Kodunuz çok hızlı çalışıyor ancak sıralı diziyi algılayamıyor . Örnek array(1 => 'a', 0 => 'b', 2 => 'c')olacak falseolması gerekirken (ardışık dizisi) true(ilişkili dizi). toolsqa.com/data-structures/array-in-programming Anahtarın artan düzende olduğundan emin değilim? (0, 1, ...)
vee

132

Elbette bu daha iyi bir alternatif.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;

52
Bu, dizideki değerleri çoğaltacaktır, bu da çok pahalı olabilir. Dizi anahtarlarını incelemek çok daha iyi.
meagar

8
Ben sadece ==; Burada === 'a ihtiyaç olduğunu düşünmüyorum. Ancak "unset ve çalışmıyor" yanıtını vermek için: ilk öğeyi unset bir kez, artık 0'dan başlayan bir tamsayı dizinli dizi değildir. Yani IMO çalışır.
grantwparks

4
@Grantwparks ile aynı fikirde: Seyrek bir dizi dizine eklenmemiş. İlginç bir şekilde, aslında bir dizini dizinlenmiş bir dizinin ortasından silmenin bir yolu olmadığı için PHP temel olarak tüm dizileri ilişkisel ve sayısal olarak bildiriyor.
RickMeasham

7
Bununla ilgili tek sorun ===, biz sadece anahtarlar ilgilenen olsa bile, değerlerin eşit olup olmadığını kontrol zaman kaybı olacaktır. Bu nedenle $k = array_keys( $arr ); return $k === array_keys( $k );sürümü tercih ederim .
Jesse

5
Eklenen bir not, arızalı sayısal tuşlarla belirtilen dizilerde başarısız olur. örneğin $ myArr = dizi (0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3'); Etrafta bir potansiyel çalışma testi yapmadan önce ksort ($ arr) çalıştırmak
Scott

77

Bu sorudaki birçok yorumcu, dizilerin PHP'de nasıl çalıştığını anlamıyor. Gönderen dizi belgeler :

Anahtar bir tamsayı veya bir dize olabilir. Anahtar bir tamsayının standart temsiliyse, bu şekilde yorumlanır (yani "8" 8, "08" ise "08" olarak yorumlanır). Anahtardaki kayan noktalar tam sayıya kısaltılır. Dizinlenmiş ve ilişkilendirilebilir dizi türleri, PHP'de aynı türde olup, hem tamsayı hem de dize dizinleri içerebilir.

Diğer bir deyişle, "8" dizisi anahtarı diye bir şey yoktur, çünkü her zaman (sessizce) tamsayı 8'e dönüştürülecektir. Dolayısıyla, tamsayılar ve sayısal dizgiler arasında ayrım yapmaya çalışmak gereksizdir.

Dizinin bir kısmının (array_keys () yaptığı gibi) veya tümünü (foreach gibi) bir kopyasını oluşturmadan tamsayı olmayan anahtarlar için bir diziyi kontrol etmenin en etkili yolunu istiyorsanız:

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

Bu, geçerli dizi konumu geçersiz olduğunda NULL döndürdüğü ve NULL hiçbir zaman geçerli bir anahtar olamayacağı için çalışır (NULL bir dizi anahtarı olarak kullanmaya çalışırsanız sessizce "" biçimine dönüştürülür).


Bu, sıralı olmayan tamsayı anahtarları için çalışmaz. [2 => 'a', 4 => 'b'] ile deneyin.
DavidJ

2
@DavidJ, "Çalışmıyor" ile ne demek istiyorsun? Tüm tuşların tamsayı olduğunu başarıyla belirler. Yayınladığınız gibi bir dizinin "sayısal dizi" olarak görülmemesi gerektiğini mi iddia ediyorsunuz?
coredumperror

7
Olmayan bir ilişkisel dizi arasında değişen anahtarlar olmalıdır 0için count($array)-1bu sıkı sırayla. İle bir ön kontrol is_array()yardımcı olabilir. Anahtar sırasını kontrol etmek için artan bir değişken ekleyin: for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;Bu anlaşmayı halleder.
ofavre

2
foreachAçık yineleme yerine kullanmak yaklaşık iki kat daha hızlıdır.
ofavre

1
Bunu bir fonksiyona dönüştürmek istiyorsanız: function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
GreeKatrina

39

OP tarafından belirtildiği gibi :

PHP tüm dizileri birleştirici olarak ele alır

bir dizinin ilişkilendirilebilir olup olmadığını kontrol eden bir işlev yazmak oldukça mantıklı değildir (IMHO) . İlk önce: PHP dizisindeki anahtar nedir ?:

Anahtar ya bir olabilir tamsayı veya bir dize .

Bu, 3 olası durum olduğu anlamına gelir:

  • Durum 1. tüm tuşlar sayısal / tamsayılardır .
  • Durum 2. tüm anahtarlar dizgidir .
  • Durum 3. bazı anahtarlar dize , bazı anahtarlar sayısal / tamsayılar .

Her bir durumu aşağıdaki işlevlerle kontrol edebiliriz.

Durum 1: tüm tuşlar sayısal / tamsayılardır .

Not : Bu işlev boş diziler için de doğru değerini döndürür .

//! 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);
}

Durum 2: tüm tuşlar dizedir .

Not : Bu işlev boş diziler için de doğru değerini döndürür .

//! 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);
}

Durum 3. bazı anahtarlar dize , bazı anahtarlar sayısal / tamsayılar .

Not : Bu işlev boş diziler için de doğru değerini döndürür .

//! 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;
}

Şunu izler:


Şimdi, bir dizinin hepimizin alışkın olduğu "orijinal" bir dizi olması, yani:

  • Anahtarları tamamen sayısal / tamsayılardır .
  • Anahtarları sıralı (yani adım 1 artarak).
  • Anahtarları sıfırdan başlar .

Aşağıdaki fonksiyon ile kontrol edebiliriz.

Durum 3a. anahtarlar sayısal / tamsayılar , sıralı ve sıfır tabanlıdır .

Not : Bu işlev boş diziler için de doğru değerini döndürür .

//! 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);
}

Uyarılar / Tuzaklar (veya PHP'deki dizi anahtarları hakkında daha da tuhaf gerçekler)

Tam sayı tuşları

Bu dizilerin anahtarları tamsayılardır :

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

Dize tuşları

Bu dizilerin anahtarları dizedir :

array("fish and chips" => "b");
array("" => "b");                                   // An empty string is also a string.
array("stackoverflow_email@example.com" => "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!

Dizgiye benzeyen tamsayı tuşları

Eğer anahtar düşünüyorsanız array("13" => "b")bir olduğunu dize , yanılıyorsunuz . Buradaki dokümandan :

Geçerli tamsayılar içeren dizeler tamsayı türüne dönüştürülür. Örneğin, "8" tuşu 8'in altında saklanacaktır. Öte yandan "08" geçerli bir ondalık tam sayı olmadığından kullanılmayacaktır.

Örneğin, bu dizilerin anahtarı tamsayılardır :

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

Ancak bu dizilerin anahtarı dizelerdir :

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.

Dahası, dokümana göre ,

Bir tamsayının boyutu platforma bağlıdır, ancak yaklaşık iki milyarlık bir maksimum değer olağan değerdir (32 bit imzalı). 64 bit platformlar, genellikle her zaman 32 bit olan Windows hariç maksimum 9E18 değerine sahiptir. PHP imzasız tam sayıları desteklemez.

Bu nedenle, bu dizinin anahtarı bir tamsayı olabilir veya olmayabilir - platformunuza bağlıdır.

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

Daha da kötüsü, PHP buggy olma eğilimindedir tam sayı 2 31 = 2.147.483.648 sınırına yakınsa (bkz. Hata 51430 , hata 52899 ). Örneğin, (Windows 7 üzerinde XAMPP 1.7.7 PHP 5.3.8) benim yerel çevre üzerindeki, var_dump(array("2147483647" => "b"))verir

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

ancak kod pedindeki bu canlı demoda (PHP 5.2.5), aynı ifade

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

Anahtar bir ortamda bir tamsayı ama bir dize2147483647 geçerli bir imzalı 32 bit tam sayı olsa da , .


2
Dışında, aşağıda belirttiğim gibi, denetlenen diziye yinelenen bir dizi oluşturmayı, büyük diziler için çok pahalı hale getirmeyi ve paylaşılan ana makinelerde potansiyel bir bellek yetersizliği kaynağı oluşturmayı içerir.
podperson

35

Hız-bilge:

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

Hafıza-bilge:

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

şu dizi: dizi (02 => 11,1,2,456); 02 === 2
Galileo_Galilei

20
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

2
Bu sadece $ dizi = array (0 => 'selam', 2 => 'evet', 3 => 'wahey'): Aşağıdakilerden başa çıkabilirim (benim yorumun anda) cevap
Shabbyrobe

ama array('1'=>'asdf', '2'=>'too')aslında olmasa da ilişkisel dizi olarak kabul edilecektir (anahtarlar aslında dize)
Kaptan kurO

1
@CaptainkurO Sayısal demek istediniz. İlişkisel bir dizidir.
devios1

1
Bu işlev true, tuşlar: sıfır, tamsayılar (yalnızca pozitif), boş bir dize veya yukarıdaki "09" dizesi gibi herhangi bir birleşimi olduğunda döndürür. Bu işlev, tuşların sırasını dikkate almaz. Yani array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey')ve array('blah', 'yep', 'wahey')hepsi bu işleve göre çağrışımsaldır, ancak array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')değildir.
Pang

@CaptainkurO yanlış. '1' ve '2' tamsayı olarak saklanır. Sincapın cevabının alıntılanan kısmını 11 Mayıs 2011 19:34'te okuyun. PHP tamsayıya benzeyen dize anahtarlarını depolamaz. Bunları tamsayılara dönüştürür.
Buttle Butkus

20

Aslında en etkili yol şudur:

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

Bu, anahtarları (sıralı dizi için her zaman 0,1,2 vb. Olan) anahtarların anahtarlarıyla ( her zaman 0,1,2 vb.) Karşılaştıracağı için çalışır.


1
Zeki, ama iyi değil. Neden bu "en verimli"? Dizi_anahtarlarını ($ a) aralık (0, sayı ($ a)) ile karşılaştırmak çok daha okunaklı olacaktır. En akıllı çözüm nadiren tecrübelerimin en iyisi. Özellikle zeki olmak, bariz ve temiz alternatif üzerinde tam anlamıyla bir değer katmaz.
Shane H

4
Bu işlev döndürür trueiçin array(1=>"a")ama falseiçin array("a"=>"a"). Onunla !=değiştirilirse daha anlamlı olur !==.
Pang

1
@ Haklısın. Yorumunuzun ilk başta mutlaka yanlış olması gerektiğini düşündüm, ama, sürpriz olarak, [0] == ['a']PHP'de (o zamandan beri 0 == 'a', ve gerçekten de 0 == 'banana'). PHP'nin ==operatörü çılgın.
Mark Amery

2
Dizi_anahtarları çağırmak ve sıralı olmayan bir tam sayı dizini bulana kadar kontrol etmek kadar etkili değildir. Başlığın altında bunu zaten yapıyorsun , ama zaten büyük bir dizi çoğalttın.
podperson

17

Her ikisini de kullandım array_keys($obj) !== range(0, count($obj) - 1)ve array_values($arr) !== $arr(birbirinin ikilisi, ikincisi birinciden daha ucuz olmasına rağmen) ama her ikisi de çok büyük diziler için başarısız.

Bunun nedeni array_keysve array_valuesher ikisi de çok maliyetli işlemlerdir (çünkü orijinalin kabaca tamamen yeni bir boyut dizisi oluşturdukları için).

Aşağıdaki işlev, yukarıda sağlanan yöntemlerden daha sağlamdır:

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;
}

Ayrıca, seyrek dizileri ilişkilendirilebilir dizilerden ayırmak istemezseniz, 'assoc'her iki ifbloktan da geri dönebileceğinizi unutmayın .

Son olarak, bu sayfadaki birçok "çözümden" çok daha az "zarif" görünse de, pratikte çok daha verimlidir. Hemen hemen tüm ilişkilendirilebilir diziler anında algılanacaktır. Yalnızca dizine alınmış diziler ayrıntılı bir şekilde denetlenir ve yukarıda açıklanan yöntemler yalnızca dizine alınmış dizileri ayrıntılı bir şekilde denetlemekle kalmaz, aynı zamanda çoğaltır.


13

Aşağıdaki iki işlev 'bir dizi ilişkisel veya sayısal olup olmadığını' denetlemek için gitmek için en iyi yol olduğunu düşünüyorum. 'Sayısal' yalnızca sayısal anahtarlar veya yalnızca sıralı sayısal anahtarlar anlamına gelebileceğinden, her iki koşulu da denetleyen iki işlev aşağıda listelenmiştir:

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));
}

İlk fonksiyon, her tuşun bir tamsayı olup olmadığını kontrol eder. İkinci fonksiyon, her bir anahtarın bir tamsayı olup olmadığını kontrol eder ve ek olarak, tüm anahtarların $ base'den başlayarak sıralı olup olmadığını kontrol eder, bu da varsayılan olarak 0 olur ve başka bir temel değer belirtmeniz gerekmiyorsa atlanabilir. Okundu işaretçisi dizinin sonunu geçerse, ($ my_array) tuşu null değerini döndürür; bu, for döngüsünü sonlandıran ve tüm anahtarların tamsayı olması durumunda for döngüsünün ardından gelen ifadeyi true yapar. Değilse, bir anahtar tür dizgisi olduğundan ve for döngüsünün sonundaki deyim yanlış döndüreceği için döngü erken sona erer. İkinci fonksiyon ek olarak, bir sonraki anahtarın doğru değerde olup olmadığını kontrol edebilmek için her karşılaştırmadan sonra bir $ base ekler. Sıkı karşılaştırma, anahtarın tamsayı tipinde olup olmadığını da kontrol etmesini sağlar. For döngüsünün ilk bölümündeki $ base = (int) $ base bölümü, $ base atlandığında veya yalnızca bir tamsayı kullanılarak çağrıldığından emin olduğunuzda dışarıda bırakılabilir. Ama herkes için emin olamadığım için, onu bıraktım. İfade zaten bir kere icra edildi. Bence bunlar en verimli çözümler:

  • Bellek açısından: Verilerin veya anahtar aralıklarının kopyalanması gerekmez. Bir dizi_değeri veya dizi_anahtarı yapmak daha kısa (daha az kod) görünebilir, ancak bu çağrıyı yaptıktan sonra arka planda neler olduğunu unutmayın. Evet, diğer bazı çözümlerden daha fazla (görünür) ifade var, ama önemli olan bu değil, değil mi?
  • Zaman açısından: Verilerin ve / veya anahtarların kopyalanması / çıkarılmasının da zaman almasının yanı sıra, bu çözüm bir foreach yapmaktan daha verimlidir. Yine, bir foreach bazıları için daha verimli görünebilir, çünkü gösterimde daha kısadır, ancak arka planda foreach de reset, key ve sonraki döngüleri çağırır. Ancak buna ek olarak, burada tamsayı kontrolü ile kombinasyon nedeniyle kaçınılmış olan son koşulu kontrol etmek için de geçerlidir.

Bir dizi anahtarının yalnızca bir tamsayı veya bir dize olabileceğini ve "1" (ancak "01" değil) gibi kesin bir sayısal dize bir tamsayıya dönüştürüleceğini unutmayın. Dizinin ardışık olmasını istiyorsanız saymanın yanı sıra tek tam sayı anahtarının denetlenmesini sağlayan da budur. Doğal olarak, is_indexed_array yanlış döndürürse dizi ilişkilendirilebilir olarak görülebilir. 'Görüldü' diyorum, çünkü aslında hepsi öyle.


1
Bu en iyi cevap. "İlişkilendirici" veya "sayısal" dizi tanımı belirli duruma bağlıdır.
Pato

Eğer foreach burada kullanılan yöntemden daha az verimli ise, o zaman iki farklı fonksiyon kullanmanın zorluğunun yanı sıra, bu çözümün performansı benimkinden (önceki) daha iyidir. Ben foreach bir dizi üzerinden gitmek için en hızlı yolu olarak tavsiye çünkü, şüpheli değil.
podperson

7

Bu işlev şunları yapabilir:

  • dizinde delikleri olan dizi (ör. 1,2,4,5,8,10)
  • "0x" tuşlarına sahip bir dizi: örn. '08' tuşu ilişkilendirilebilirken '8' tuşu sıralıdır.

fikir basittir: tuşlardan biri tamsayı DEĞİLSE, ilişkilendirilebilir bir dizidir, aksi takdirde sıralı olur.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}

1
"Anahtarlardan biri tamsayı DEĞİLDİR, ilişkilendirilebilir dizi, aksi takdirde sıralı" - ha? Hayır, bu sadece yanlış. "İlişkisel" bir diziyi neyin oluşturduğuna dair tartışmalar için yer vardır, ancak "sıralı" ifadesinin anlamı oldukça açıktır ve tüm tuşların sayı olmasıyla aynı değildir.
Mark Amery

Anahtarlardan biri doğa tarafından ilişkilendirilebilecek bir tamsayı DEĞİLSE, ancak anahtarlar 0 - uzunluk (dizi) - 1 arasındaysa sıralı olur. Ancak, tüm tuşlar yalnızca numaralandırılmışsa, SAYISALDIR, ancak veya sıralı dizi gerektiren birçok dizi işleviyle çalışmayabilir. Delikli sayısal diziyi, üzerinde array_values ​​(dizi) çalıştırarak sırayla dönüştürürseniz, sıraya dönüştürülür.
geilt

7

Bu soru için iki popüler yaklaşım fark ettim: biri kullanma array_values()diğeri kullanma key(). Hangisinin daha hızlı olduğunu bulmak için küçük bir program yazdım:

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

CentOS üzerinde PHP 5.2 program çıktısı aşağıdaki gibidir:

Yöntem # 1 = 10.745ms
ile alınan zaman Yöntem # 2 = 18.239ms ile alınan zaman

PHP 5.3 çıktısı da benzer sonuçlar verdi. Açıkçası kullanmak array_values()çok daha hızlı.


kötü kriter. Büyük dizileri test etmediniz. Bilgisayarımda 10K + elementlerden başlayan yöntem # 2 daha hızlı. Deneyin$arrays = Array( 'Array #1' => range(0, 50000), );
nonsensei

7

Buna yaklaşmanın bir yolu json_encode, doğru JSON çıktısını almak için ilişkilendirilebilir bir dizi ile dizinli bir dizi arasında ayrım yapmak için zaten kendi dahili yöntemine sahip olan bindirme yöntemidir.

Kodlamadan sonra döndürülen ilk karakterin bir {(ilişkilendirilebilir dizi) mi yoksa [(dizine alınmış bir dizi) olup olmadığını kontrol ederek bunu yapabilirsiniz .

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}

Bence ksort () gerekli değil. Bu çözüm çalışıyor, ancak $ arr null olup olmadığını ve json_encode başarısız olup olmadığını sınamak zorunda, bu yüzden bir try / catch. + $ arr büyükse gerçekten uygun değildir.
lucbonnin

7

Zaten birçok cevap var, ancak Laravel'in Arr sınıfı içinde dayandığı yöntem:

/**
 * 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;
}

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


1
@Casey array_keys($keys), orijinal diziyle aynı uzunlukta olan sıralı bir sayı dizisi (0 ... X) döndürür. Örneğin array_keys(["a", "b", "c"]) = [0, 1, 2]; array_keys([0, 1, 2]) = [0, 1, 2](sıralı bir dizi çünkü [0, 1, 2] !== [0, 1, 2]). Başka bir örnek: array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"]; array_keys(["a", "b", "c"]) = [0, 1, 2](çünkü ilişkilendirilebilir bir dizi ["a", "b", "c"] !== [0, 1, 2]). Umarım açıktır (bir yorumda, en azından benim için kapsamlı olarak açıklamak zor)
valepu

Bu algoritma çılgın, kolay, anlaşılır.
Benyi

İlişkili satırların sıralı bir dizisine sahipseniz bu çalışmaz.
lucbonnin

5
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

Hızlı, özlü ve bellek tasarruflu. Pahalı karşılaştırmalar, işlev çağrıları veya dizi kopyalama yok.


4

Xarray PHP eklentisini kullanarak

Bunu çok hızlı yapabilirsiniz (PHP 5.6'da yaklaşık 30+ kat daha hızlı):

if (array_is_indexed($array)) {  }

Veya:

if (array_is_assoc($array)) {  }

3

Bu büyük kuyruğa bir cevap ekleyerek biraz anlamsız olduğunu biliyorum, ancak burada herhangi bir değeri çoğaltmayı gerektirmeyen okunabilir bir O (n) çözümü:

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

Tümünün sayısal olup olmadığını görmek için tuşları kontrol etmek yerine, sayısal bir dizi için orada olacak tuşlar üzerinde tekrarlar ve var olduklarından emin olursunuz .


bir nokta daha. formdaki dizi [1,2,null,4]başarısız olur, ancak doğru dizidir. bu yüzden ek kontrol ile stackoverflow.com/a/25206156/501831 bazı geliştirmeler ekledim array_key_exists)
lazycommit

1; isset()burada yanlış bir araçtır çünkü değer ayarlanmışsa false döndürür ancak null@lazycommit tarafından işaret edildiği gibi.
Mark Amery

3

Çözümüm:

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

array_mergetek bir dizide tüm integeranahtarları yeniden dizine ekler , ancak diğer anahtarları yeniden dizilmez . Örneğin:

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

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

Dolayısıyla, bir liste (ilişkisel olmayan bir dizi) oluşturulursa, ['a', 'b', 'c']bir değer kaldırılır ve unset($a[1])sonra array_mergeçağrılır, liste 0'dan başlayarak yeniden dizine eklenir.


1; bu, O(n)kullanılan ek hafızadadır (çok sayıda öğeye sahip birden çok yeni diziler oluşturduğundan $array), yanıt, sorulan sorunun belirsizliğini ele almaz ve bir liste / ilişkisel olmayan diziyi nasıl tanımladığını açıklamaz ve hatta eğer bu noktalardan hiçbiri doğru değilse, bunun zaten gönderilen diğer cevaplara kıyasla herhangi bir değer kattığı açık değildir.
Mark Amery

3

Bazı yerel kıyaslama, hata ayıklama, derleyici problama, profilleme ve 3v4l.org'u daha fazla versiyonda kıyaslamak için (evet, durmak için bir uyarı aldım) ve bulabildiğim her varyasyonla karşılaştırarak ...

Sana bir organik kökenli vermek en iyisi ortalama kötü senaryo olan ilişkisel dizi test işlevi en kötü kabaca iyi olduğu kadar ya da daha iyi, diğer tüm ortalama durum senaryoları daha.

/**
 * 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;
}

Gönderen 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";
}

2

İşte kullandığım yöntem:

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

Bunun aşağıdaki gibi özel durumları hesaba katmadığını unutmayın:

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

unset($a[1]);

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

Üzgünüm, bu konuda sana yardım edemem. Gereksiz kopyalar üretmediğinden, düzgün boyutlandırılmış diziler için de bir miktar performans gösterir. Python ve Ruby'yi yazmak için çok güzel yapan bu küçük şeyler ...: P


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);
}

?>

En çok puan alan bu örneklerin her ikisi de aşağıdaki gibi dizilerle düzgün çalışmaz $array = array('foo' => 'bar', 1)


+1 is_list () cihazınız IMO en iyi yanıttır. Bazı insanlar zaman ve alan karmaşıklığı ve yerli vs PHP komut dosyası fonksiyonu hakkında bir ipucu yok ...
e2-e4 16:00

2

Bu da işe yarar ( demo ):

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

Lütfen bu cevabın ana amacının varlığı hakkında sizi bilgilendirmek SplFixedArrayve sizi bu tür testler için İstisnalar kullanmaya teşvik etmemek olduğunu unutmayın.


2

Bence skaler dizinin tanımı uygulamaya göre değişecektir. Yani, bazı uygulamalar, skaler dizi olarak neyin nitelendirildiğine dair daha katı bir his gerektirir ve bazı uygulamalar daha gevşek bir his gerektirir.

Aşağıda 3 farklı değişkenlik yöntemi sunuyoruz.

<?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 <DavidPFarrell@gmail.com>
 */

/**
 * 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;
}

2

Kaynaktan bir tane daha hızlı . json_encode(Ve bson_encode) kodlamasını sığdırın . Javascript Array uyumluluğu da öyle.

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__)
        );
    }
}

1
Neden issetve array_key_exists? ikincisi yeterli olmaz mı?
mcfedr

@mcfedr evet, olur - buradaki isset()kontrol tamamen gereksizdir.
Mark Amery

@mcfedr, performans nedenlerinden dolayı @ mark-amery. isset()daha hızlıdır array_key_exists(). bkz. ilia.ws/archives/…
lazycommit

@lazycommit Daha sonra onun olsun ya da olmasın daha iyi, senin dizi bağlıdır olacak nulls çok sayıda bir dizi olması muhtemel değil, ama aynı zamanda büyük olasılıkla farkedilir performans farkı olacak kadar büyük bir dizi var her iki kontrolü kullanarak
mcfedr

2
Eğer uyabilecek olmadığını kontrol etmek gerekiyorsa json_encode, sadece tarafından döndürülen dize ilk sembolü, kontrol edebilir json_encode($your_arr), bu ister - [veya {;-)
Piłat

2

Çözüm bu olabilir mi?

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

Açıkçası dizi imlecinin sıfırlanmış olduğu açıktır, ancak muhtemelen dizi geçmeden veya kullanılmadan önce fonksiyonun kullanıldığını söyleyebilirim.


Bu işlev her ikisi için de false değerini döndürür array("a", "b")ve array("a", "b" => "B")yalnızca ilk anahtarı denetlediğinden. BTW, is_longsadece bir takma addıris_int .
Pang

1
açıkçası bu durumun büyük çoğunluğunda çok etkili olacağını ve alternatiflerden çok daha verimli olacağını düşünüyorum. Bu yöntemin sonuçlarını anlar ve bunun sizin için çalışacağını fark ederseniz, muhtemelen en iyi seçimdir.
Gershom

Bu sadece yanlış; sadece ilk anahtara bakar.
Mark Amery

@MarkAmery sorusu, tamamen sıralı dizilerin tamamen ilişkilendirilebilir dizilerden nasıl ayırt edileceğini sordu . Bu cevap tam olarak bunu yapar ve hepsinden en etkilisidir. Karışık diziler için tanımlanmamış davranışa sahip olmak , soru bağlamında gayet iyi. +1
Tobia

@Tobia Çoğu insanın [7 => 'foo', 2 => 'bar'], kısmen, ancak "tamamen" ardışık olmayan "karışık" bir dizi olarak sınıflandırılmasını kabul edeceğini sanmıyorum . Bu benim için kelimelerin yanlış kullanımı gibi görünüyor.
Mark Amery

2

Buradaki birçok çözüm zarif ve güzel, ancak iyi ölçeklenmiyor ve bellek yoğun veya CPU yoğun. Çoğu, karşılaştırmanın her iki tarafından bu çözüm ile bellekte 2 yeni veri noktası oluşturuyor. Dizi ne kadar büyük olursa, kullanılan işlem ve bellek o kadar zorlaşır ve kısa devre değerlendirmesinin avantajını kaybedersiniz. Birkaç farklı fikirle bazı testler yaptım. Array_key_exists maliyetlidir gibi önlemek ve aynı zamanda karşılaştırmak için yeni büyük veri kümeleri oluşturmaktan kaçının. Bu bir dizi ardışık olup olmadığını söylemek için basit bir yol olduğunu hissediyorum.

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;
}

Ana dizi üzerinde tek bir sayı çalıştırırsınız ve tek bir tamsayı depolarsınız. Daha sonra dizi boyunca döngü yaparsınız ve sayacı yinelerken tam eşleşmeyi kontrol edersiniz. 1'den saymanız gerekir. Başarısız olursa kısa devre yapar, bu da yanlış olduğunda size performans artışı sağlar.

Başlangıçta bunu bir for döngüsü ve isset ($ arr [$ i]) için yaptım ama bu array_key_exists gerektiren boş anahtarları algılamayacak ve bildiğimiz gibi hız için kullanılacak en kötü işlev.

Sürekli olarak foreach aracılığıyla değişkenleri sürekli olarak güncelleyerek, yineleyici ile birlikte tamsayı boyutunun ötesine geçmez, PHP'nin sizi çok düşük kaynak kullanımında tutmak için bellek optimizasyonu, önbellekleme ve çöp toplamada kullanmasına izin verir.

Ayrıca, sadece $ key => $ değeri çalıştırabilir ve anahtarı kontrol edebilirsiniz bir foreach içinde array_keys kullanarak aptal olduğunu iddia edeceğiz. Neden yeni veri noktasını oluşturmalısınız? Dizi anahtarlarını soyutladıktan sonra hemen daha fazla bellek tüketmiş olursunuz.


1

cevaplar zaten verildi, ancak performans hakkında çok fazla dezenformasyon var. Foreach yönteminin en hızlı olduğunu gösteren bu küçük kıyaslama komut dosyasını yazdım.

Feragatname: aşağıdaki yöntemler diğer cevaplardan kopyalandı

<?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";
}

Sonuçlar:

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

1

Veya bunu sadece kullanabilirsiniz:

Arr::isAssoc($array)

dizinin sayısal olmayan bir anahtar içerip içermediğini kontrol eder veya:

Arr:isAssoc($array, true)

dizinin kesin olarak ardışık olup olmadığını kontrol etmek için ( 0 ile n-1 arasında otomatik oluşturulan int anahtarları içerir )

bu kütüphaneyi kullanarak .


0

PHP bunun için bir yerleşik değilse, tüm anahtarları numaralandırarak ve tamsayı türünü kontrol ederek O (n) 'den daha azıyla yapamazsınız. Aslında, delik olmadığından da emin olmak istersiniz, bu nedenle algoritmanız aşağıdaki gibi görünebilir:

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

Ama neden rahatsız oluyorsun? Dizinin beklediğiniz türde olduğunu varsayalım. Değilse, sadece yüzünüzde patlayacak - bu sizin için dinamik bir programlama! Kodunuzu test edin ve hepsi iyi olacak ...


1
Normalde sadece dizinin istenen tip olduğunu varsayarsak gitmek için bir yol olacaktır. Ama benim durumumda çok boyutlu bir dizi üzerinden döngü ve belirli bir düğüm tür dizi bağlı olarak çıktı biçimlendiriyorum.
Wilco

0

Her zaman tamsayı dizinleri olan bir dizi olacak dizinin anahtarları ile dizinin array_values ​​() sonucunun anahtarları arasındaki farkı karşılaştırırım. Anahtarlar aynıysa, ilişkilendirilebilir bir dizi değildir.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}

1; bu , öğeleri O(n)olduğunda ek bellek kullanır ve bunun yerine yazma korkunç ve zahmetli bir şekilde ayrıntılıdır. $arrayn(someboolean) ? false : true!someboolean
Mark Amery
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.