Jak sprawdzić, czy tablica PHP jest asocjacyjna czy Sekwencyjna?

PHP traktuje wszystkie tablice jako asocjacyjne, więc nie ma żadnych wbudowanych funkcji. Czy ktoś może polecić dość skuteczny sposób sprawdzenia czy tablica zawiera tylko klucze numeryczne?

W zasadzie chcę być w stanie odróżnić to:

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

I to:

$assocArray = array('fruit1' => 'apple', 
                    'fruit2' => 'orange', 
                    'veg1' => 'tomato', 
                    'veg2' => 'carrot');
 681
Author: Wilco, 2008-10-06

30 answers

Zadałeś dwa pytania, które nie są do końca równoważne:

  • Po pierwsze, jak określić, czy tablica ma tylko klucze numeryczne
  • Po drugie, jak określić, czy tablica ma sekwencyjne klucze numeryczne, począwszy od 0
Zastanów się, które z tych zachowań naprawdę potrzebujesz. (Może być tak, że albo zrobi to dla Twoich celów.)

Pierwsze pytanie (po prostu sprawdzanie, czy wszystkie klucze są numeryczne) to dobrze odpowiedział Kapitan kurO .

W drugim pytaniu (sprawdzanie, czy tablica jest indeksowana zerowo i sekwencyjnie), możesz użyć następującej funkcji:

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

var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false
var_dump(isAssoc(array("1" => 'a', "0" => 'b', "2" => 'c'))); // true
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
 515
Author: Mark Amery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-30 21:13:24

Aby tylko sprawdzić, czy tablica ma klucze nie-całkowite (nie, czy tablica jest indeksowana sekwencyjnie, czy indeksowana zero):

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

Jeśli istnieje co najmniej jeden klucz Łańcuchowy, $array będzie traktowany jako tablica asocjacyjna.

 393
Author: Captain kurO,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-25 16:26:58

Z pewnością jest to lepsza alternatywa.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
 122
Author: Dave Marshall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-21 13:20:37

Wielu komentujących to pytanie nie rozumie jak tablice działają w PHP. Z dokumentacji tablicy :

Klucz może być liczbą całkowitą lub łańcuchem znaków. Jeśli klucz jest standardową reprezentacją liczby całkowitej, będzie on interpretowany jako taki (tzn. "8" będzie interpretowane jako 8, podczas gdy "08" będzie interpretowane jako "08"). Pływaki w kluczu są obcięte do liczby całkowitej. Typy tablic indeksowanych i asocjacyjnych są tym samym typem w PHP, który może zawierać zarówno liczbę całkowitą, jak i ciąg znaków indeksy.

Innymi słowy, nie ma czegoś takiego jak klucz tablicy "8", ponieważ zawsze będzie on (po cichu) konwertowany na liczbę całkowitą 8. Więc próba odróżnienia liczb całkowitych od ciągów liczbowych jest niepotrzebna.

Jeśli chcesz najbardziej efektywny sposób sprawdzania tablicy pod kątem kluczy innych niż liczby całkowite bez tworzenia kopii części tablicy (tak jak array_keys ()) lub jej całości (tak jak foreach):

for (reset($my_array); is_int(key($my_array)); next($my_array));
$onlyIntKeys = is_null(key($my_array));

To działa, ponieważ key () zwraca NULL, gdy bieżąca tablica position jest niepoprawne i NULL nigdy nie może być poprawnym kluczem(jeśli spróbujesz użyć NULL jako klucza tablicy, zostanie on po cichu przekonwertowany na"").

 73
Author: squirrel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-11 19:34:45

Jako podane przez OP :

PHP traktuje wszystkie tablice jako asocjacyjne

Nie jest całkiem sensowne (IMHO) pisanie funkcji sprawdzającej, czy tablica jest asocjacyjna. Więc po pierwsze: co to jest klucz w tablicy PHP ?:

Klucz Może Być albo liczbą całkowitą lub łańcuchem .

Oznacza to, że są 3 możliwe przypadki:

  • Przypadek 1. wszystkie klucze są numeryczny / liczby całkowite .
  • Przypadek 2. wszystkie klucze są ciągami .
  • Przypadek 3. niektóre klucze są ciągami , niektóre klucze są liczbowe / liczby całkowite .

Możemy sprawdzić każdy przypadek za pomocą następujących funkcji.

Przypadek 1: wszystkie klucze są liczbowe / liczby całkowite .

Uwaga: funkcja zwraca true również dla pustych tablic.

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

Przypadek 2: wszystkie klucze to ciągi .

Uwaga: funkcja zwraca true również dla pustych tablic.

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

Przypadek 3. niektóre klucze są ciągami , niektóre klucze są liczbowe / liczby całkowite .

Uwaga: funkcja zwraca true również dla pustych tablic.

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

Wynika z tego, że:


Teraz, aby tablica była "prawdziwą" tablicą że wszyscy jesteśmy przyzwyczajeni do, znaczenie:

  • jego klucze są wszystkie liczbowe / liczby całkowite .
  • jego klucze są sekwencyjne (tzn. zwiększają się o krok 1).
  • jego klucze zacznij od zera.

Możemy sprawdzić za pomocą następującej funkcji.

Przypadek 3a. klucze są liczbowe / liczby całkowite, sekwencyjne i oparte na zero .

Uwaga: Funkcja ta zwraca true również dla pustych tablic.

//! 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);
}
[182]} błędy / pułapki (lub jeszcze bardziej osobliwe fakty na temat kluczy tablicowych w PHP)

Klucze całkowite

Klucze dla tych tablic to liczby całkowite:

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

Klucze strunowe

Klucze dla tych tablic to struny:

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!

Klucze całkowite wyglądające jak łańcuchy

Jeśli uważasz, że kluczem w array("13" => "b") jest łańcuch, jesteś wrong . Z doc tutaj :

Ciągi zawierające poprawne liczby całkowite zostaną oddane do typu integer. Np. klucz " 8 " będzie faktycznie przechowywany pod numerem 8. Z drugiej strony "08"nie zostanie rzucona, ponieważ nie jest poprawną liczbą dziesiętną.

Na przykład klucz dla tych tablic to liczby całkowite :

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

Ale kluczem dla tych tablic są ciągi :

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.

Co więcej, zgodnie z doc ,

Wielkość liczby całkowitej jest zależna od platformy, chociaż maksymalna wartość około dwóch miliardów jest zwykłą wartością (to 32 bity podpisane). Platformy 64-bitowe zwykle mają maksymalną wartość około 9E18, z wyjątkiem Windows, który jest zawsze 32 bit. PHP nie obsługuje niepodpisanych liczb całkowitych.

Więc klucz dla tej tablicy może lub nie być liczbą całkowitą - to zależy od twojej platformy.

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

Co gorsza PHP ma tendencję do buggy jeśli liczba całkowita znajduje się w pobliżu 231 = 2,147,483,648 boundary (see bug 51430, bug 52899 ). Na przykład w moim środowisku lokalnym (PHP 5.3.8 na XAMPP 1.7.7 na Windows 7), var_dump(array("2147483647" => "b")) daje

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

Ale na to demo na codepad (PHP 5.2.5), to samo wyrażenie daje

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

Więc klucz jest integer w jednym środowisku, ale string w innym, nawet jeśli 2147483647 jest poprawnym podpisanym 32-bitowym liczba całkowita.

 36
Author: Pang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:37

Speed-wise:

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

Pamięć:

function isAssoc($array)
{
    $array = array_keys($array); return ($array !== array_keys($array));
}
 32
Author: Alix Axel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-06 17:39:10
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}
 18
Author: dsims,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-03-15 02:14:41

W rzeczywistości najskuteczniejszym sposobem jest zatem:

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

To działa, ponieważ porównuje klucze (które dla tablicy sekwencyjnej są zawsze 0,1,2 itd.) z kluczami kluczy (które Zawsze będą 0,1,2 itd.).

 18
Author: 4 revs, 3 users 67%anon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-08 03:58:00

Użyłem zarówno array_keys($obj) !== range(0, count($obj) - 1) jak i array_values($arr) !== $arr (które są dualami siebie nawzajem, chociaż drugi jest tańszy niż pierwszy), ale oba zawodzą dla bardzo dużych tablic.

Dzieje się tak dlatego, że array_keys i array_values są bardzo kosztownymi operacjami (ponieważ budują zupełnie nową tablicę wielkości mniej więcej tej oryginalnej).

Następująca funkcja jest bardziej wytrzymała niż metody podane powyżej:

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

Zauważ również, że jeśli nie zależy ci na rozróżnieniu rzadkich tablic od tablic asocjacyjnych, możesz może po prostu zwrócić 'assoc' z obu if bloków.

Wreszcie, chociaż może to wydawać się znacznie mniej " eleganckie "niż wiele" rozwiązań " na tej stronie, w praktyce jest znacznie bardziej wydajne. Prawie każda tablica asocjacyjna zostanie natychmiast wykryta. Tylko indeksowane tablice będą sprawdzane w sposób wyczerpujący, a metody opisane powyżej nie tylko sprawdzają indeksowane tablice w sposób wyczerpujący, ale je powielają.

 16
Author: podperson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-02 00:13:49

Myślę, że poniższe dwie funkcje są najlepszym sposobem na sprawdzenie 'czy tablica jest asocjacyjna czy numeryczna'. Ponieważ 'numeric' może oznaczać tylko klucze numeryczne lub tylko sekwencyjne klucze numeryczne, dwie funkcje są wymienione poniżej, które sprawdzają warunek:

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

Pierwsza funkcja sprawdza, czy każdy klucz jest liczbą całkowitą. Druga funkcja sprawdza, czy każdy klucz jest liczbą całkowitą i dodatkowo sprawdza, czy wszystkie klucze są sekwencyjne zaczynając od $base, która domyślnie ma wartość 0 i dlatego może być pominięte, jeśli nie trzeba podawać innej wartości bazowej. key ($my_array) zwraca null, jeśli wskaźnik odczytu jest przesunięty poza koniec tablicy, co kończy pętlę for i sprawia, że instrukcja po pętli for zwraca true, jeśli wszystkie klucze były liczbami całkowitymi. Jeśli nie, pętla kończy się przedwcześnie, ponieważ klucz jest typu string, a instrukcja po pętli for zwróci false. Ta ostatnia funkcja dodatkowo dodaje jeden do $base po każdym porównaniu, aby móc sprawdzić, czy następny klucz jest z poprawna wartość. Ścisłe porównanie sprawia, że sprawdza również, czy klucz jest typu integer. Część $base = (int) $base w pierwszej sekcji pętli for może zostać pominięta, gdy $base jest pominięta lub jeśli upewnisz się, że jest wywołana tylko przy użyciu liczby całkowitej. Ale ponieważ nie mogę być pewny dla wszystkich, zostawiłem go w środku. Polecenie jest wykonywane tylko raz. Myślę, że są to najbardziej efektywne rozwiązania:

  • pamięć: brak kopiowania danych lub zakresów kluczy. Wykonywanie wartości array_values lub array_keys może wydaje się krótszy (mniej kodu), ale należy pamiętać, co dzieje się w tle po wykonaniu tego połączenia. Tak jest więcej (widocznych) stwierdzeń niż w niektórych innych rozwiązaniach, ale nie to się liczy, prawda?
  • czas mądry: poza tym, że kopiowanie / wyodrębnianie danych i/lub kluczy również wymaga czasu, To rozwiązanie jest bardziej wydajne niż robienie foreach. Ponownie foreach może wydawać się bardziej wydajny dla niektórych, ponieważ jest krótszy w notacji, ale w tle foreach również wywołuje reset, key i next żeby to zrobić, zapętla się. Ale ponadto wywołuje również valid, aby sprawdzić stan końcowy, który jest unikany tutaj ze względu na kombinację z sprawdzaniem liczb całkowitych.

Pamiętaj, że klucz tablicy może być tylko liczbą całkowitą lub łańcuchem znaków, a łańcuch ściśle numeryczny, taki jak " 1 "(ale nie" 01") zostanie przetłumaczony na liczbę całkowitą. Co sprawia, że sprawdzanie klucza integer jest jedyną potrzebną operacją poza zliczaniem, jeśli chcesz, aby tablica była Sekwencyjna. Oczywiście, jeśli is_indexed_array zwróci false tablica może być postrzegana jako asocjacyjna. Mówię "widziałem", bo w rzeczywistości wszystkie są.

 13
Author: Niels Ockeloen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-15 21:54:50

Ta funkcja może obsługiwać:

  • tablica z otworami w indeksie (np. 1,2,4,5,8,10)
  • tablica z klawiszami "0x": np. klucz '08' jest asocjacyjny, podczas gdy klucz ' 8 ' jest sekwencyjny.

Idea jest prosta: jeśli jeden z kluczy nie jest liczbą całkowitą, jest tablicą asocjacyjną, w przeciwnym razie jest sekwencyjną.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
 7
Author: LazNiko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-05 09:13:12

Zauważyłem dwa popularne podejścia do tego pytania: jeden za pomocą {[1] } i inne za pomocą key(). Aby dowiedzieć się, który jest szybszy, napisałem mały program:

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

Wyjście dla programu na PHP 5.2 na CentOS jest następujące:

Czas wzięty metodą # 1 = 10.745 ms
Czas wzięty metodą # 2 = 18.239 ms

Wyniki w PHP 5.3 dały podobne wyniki. Oczywiście używanie array_values() jest znacznie szybsze.

 7
Author: Manu M.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-20 10:32:10

Istnieje już wiele odpowiedzi, ale oto metoda, na której Laravel opiera się w swojej klasie Arr:

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

Źródło: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

 6
Author: Ben,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-30 21:23:10

Jednym ze sposobów podejścia do tego problemu jest użycie json_encode, która ma już własną wewnętrzną metodę rozróżniania tablicy asocjacyjnej od tablicy indeksowanej w celu uzyskania poprawnego JSON.

Możesz to zrobić, sprawdzając, czy pierwszy znak zwrócony po zakodowaniu jest { (tablica asocjacyjna) lub [ (tablica indeksowana).

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
 5
Author: MAChitgarha,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-09-10 08:31:43
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}
Szybka, zwięzła i wydajna pamięć. Brak kosztownych porównań, wywołań funkcji lub kopiowania tablic.
 4
Author: Jesse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-08 04:02:54

Używając xarray rozszerzenie PHP

Możesz to zrobić bardzo szybko (około 30+ razy szybciej w PHP 5.6):

if (array_is_indexed($array)) {  }

Lub:

if (array_is_assoc($array)) {  }
 3
Author: c9s,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-16 08:05:15

Moje rozwiązanie:

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

array_merge na jednej tablicy będzie reindex wszystkie integer klucze, ale nie inne. Na przykład:

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

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

Jeśli więc zostanie utworzona lista (tablica nie asocjacyjna) ['a', 'b', 'c'] wtedy zostanie usunięta wartość unset($a[1]) wtedy zostanie wywołana array_merge, Lista jest reindeksowana począwszy od 0.

 3
Author: ByScripts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-02 16:55:37

Oto metoda, której używam:

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

Zauważ, że nie dotyczy to szczególnych przypadków, takich jak:

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

unset($a[1]);

assert( true === is_associative($a) );
Przykro mi, nie mogę ci w tym pomóc. Jest również nieco wydajny dla przyzwoitych rozmiarów tablic, ponieważ nie tworzy niepotrzebnych kopii. To właśnie te małe rzeczy sprawiają, że Python i Ruby są o wiele przyjemniejsze do pisania... : P
 2
Author: AL the X,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-22 19:29:46
<?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);
}

?>

Oba te przykłady, które zdobyły najwięcej punktów, nie działają poprawnie z tablicami takimi jak $array = array('foo' => 'bar', 1)

 2
Author: KillEveryBody,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-16 11:28:27

To też by zadziałało ( demo):

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

Należy pamiętać, że głównym celem tej odpowiedzi jest poinformowanie Cię o istnieniu SplFixedArray, a nie zachęcanie do stosowania wyjątków dla tego rodzaju testów.

 2
Author: Gordon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-21 11:14:58

Myślę, że definicja tablicy skalarnej będzie różna w zależności od zastosowania. Oznacza to, że niektóre aplikacje będą wymagały bardziej ścisłego wyczucia tego, co kwalifikuje się jako tablica skalarna, a niektóre aplikacje będą wymagały bardziej luźnego wyczucia.

Poniżej przedstawiam 3 metody różnej ścisłości.

<?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;
}
 2
Author: David Farrell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-25 00:46:57

Czy to może być rozwiązanie?

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

Zastrzeżenie jest oczywiste, że kursor tablicy jest resetowany, ale powiedziałbym, że prawdopodobnie funkcja jest używana, zanim tablica zostanie nawet przejechana lub użyta.

 2
Author: Kat Lim Ruiz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-01-25 18:53:52

O ile PHP nie ma wbudowanego do tego elementu, nie będziesz w stanie tego zrobić w czasie krótszym niż O(n) - wyliczając wszystkie klucze i sprawdzając Typ integer. W rzeczywistości chcesz również upewnić się, że nie ma dziur, więc twój algorytm może wyglądać następująco:

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 :)
Ale po co się trudzić? Po prostu Załóżmy, że tablica jest typu, którego oczekujesz. Jeśli nie, to po prostu wybuchnie ci w twarz - to dynamiczne programowanie dla Ciebie! Przetestuj swój kod i wszystko będzie dobrze...
 1
Author: Daren Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-06 07:06:15

Wiem, że nie ma sensu dodawanie odpowiedzi do tej ogromnej kolejki, ale oto czytelne rozwiązanie O(n), które nie wymaga powielania żadnych wartości:

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

Zamiast sprawdzać klucze, aby sprawdzić, czy wszystkie są numeryczne, wykonujesz iterację nad kluczami, które byłyby dla tablicy numerycznej i upewniasz się, że istnieją.

 1
Author: cloudfeet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-10 23:29:21

Jeszcze jeden post ze źródła . Fit encoding of json_encode (and bson_encode). Tak jak zgodność z tablicami javascript.

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
Author: lazycommit,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-09 05:43:45

Odpowiedzi są już podane, ale jest zbyt wiele dezinformacji na temat wydajności. Napisałem ten mały benchmark, który pokazuje, że metoda foreach jest najszybsza.

Zastrzeżenie: następujące metody zostały skopiowane z innych odpowiedzi

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

Wyniki:

==== 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
Author: nonsensei,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-06 07:17:09

Po pewnym lokalnym benchmarkingu, debugowaniu, sondowaniu kompilatora, profilowaniu i nadużywaniu 3v4l.org do porównywania kolejnych wersji (tak, dostałem ostrzeżenie, aby przestać) i porównując z każdą odmianą jaką znalazłem...

Daję ci organicznie pochodną Najlepszy-średni-najgorszy-scenariusz asocjacyjna funkcja testu tablicy, która jest w najgorszy mniej więcej tak dobry lub lepszy niż wszystkie inne scenariusze średniego przypadku.

[[10]}niech Bóg zlituje się nad naszym dusze.
/**
 * 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;
}

Z 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";
}
 1
Author: TylerY86,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-15 07:44:02

Porównuję różnicę między kluczami tablicy a kluczami wyniku array_values () tablicy, która zawsze będzie tablicą z indeksami całkowitymi. Jeśli klucze są takie same, nie jest to tablica asocjacyjna.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}
 0
Author: philroy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-15 15:04:49

Modyfikacja najpopularniejszej odpowiedzi.
Wymaga to trochę więcej przetwarzania, ale jest bardziej dokładne.

<?php
//$a is a subset of $b
function isSubset($a, $b)
{
    foreach($a =>$v)
        if(array_search($v, $b) === false)
            return false;

    return true;

    //less effecient, clearer implementation. (uses === for comparison)
    //return array_intersect($a, $b) === $a;
}

function isAssoc($arr)
{
    return !isSubset(array_keys($arr), range(0, count($arr) - 1));
}

var_dump(isAssoc(array('a', 'b', 'c'))); // false
var_dump(isAssoc(array(1 => 'a', 0 => 'b', 2 => 'c'))); // false
var_dump(isAssoc(array("0" => 'a', "1" => 'b', "2" => 'c'))); // false 
//(use === in isSubset to get 'true' for above statement)
var_dump(isAssoc(array("a" => 'a', "b" => 'b', "c" => 'c'))); // true
?>
 0
Author: Jason McCarrell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-19 19:02:07

Moim zdaniem tablica powinna być akceptowana jako asocjacyjna, jeśli którykolwiek z jej kluczy nie jest liczbą całkowitą, np. liczba zmiennoprzecinkowa i pusty łańcuch ".

Również liczby całkowite niezsekwencjonowane muszą być postrzegane jako asocjacyjne (0,2,4,6), ponieważ tego rodzaju tablice nie mogą być używane z pętlami for w ten sposób:

$n =count($arr);
for($i=0,$i<$n;$i++) 

Druga część poniższej funkcji sprawdza czy klucze są indeksowane lub not.It działa również dla kluczy z wartościami ujemnymi. Na przykład (-1,0,1,2,3,4,5)

count() = 7 , max = 5, min=-1



if( 7 == (5-(-1)+1 ) // true
    return false; // array not associative


/** 
 * isAssoc Checks if an array is associative
 * @param $arr reference to the array to be checked
 * @return bool 
 */     
function IsAssoc(&$arr){
    $keys= array_keys($arr);
    foreach($keys as $key){
        if (!is_integer($key))
            return true;
    }
    // if all keys are integer then check if they are indexed
    if(count($arr) == (max($keys)-min($keys)+1))
        return false;
    else
        return true;
}
 0
Author: Selim Acar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-19 13:38:10