915 Stimmen

Wie prüft man, ob ein PHP-Array assoziativ oder sequentiell ist?

PHP behandelt alle Arrays als assoziativ, daher gibt es keine eingebauten Funktionen. Kann jemand einen effizienten Weg empfehlen, um zu prüfen, ob ein Array "ist eine Liste" (enthält nur numerische Tasten, die bei 0 beginnen)?

Im Grunde genommen möchte ich zwischen diesen Dingen unterscheiden können:

$sequentialArray = [
    'apple', 'orange', 'tomato', 'carrot'
];

und dies:

$assocArray = [
    'fruit1' => 'apple',
    'fruit2' => 'orange',
    'veg1' => 'tomato',
    'veg2' => 'carrot'
];

526 Stimmen

Es gibt einen Fehler in Ihrem Code: Die Tomate ist eine Frucht.

13 Stimmen

Diese Methode ist mit einigen Vorbehalten verbunden, aber ich mache oft einfach if (isset($array[0])) die einfach und schnell ist. Natürlich sollten Sie zunächst sicherstellen, dass das Array nicht leer ist, und Sie sollten einige Kenntnisse über den möglichen Inhalt des Arrays haben, damit die Methode nicht fehlschlägt (wie gemischt numerisch/assoziativ oder nicht-sequentiell).

1 Stimmen

@OlleHärstedt Nicht laut US High Court. ;-)

42voto

Pang Punkte 9023

として von der OP angegeben :

PHP behandelt alle Arrays als assoziativ

ist es (IMHO) nicht ganz sinnvoll, eine Funktion zu schreiben, die prüft, ob ein Array assoziativ . Also, das Wichtigste zuerst: Was ist ein Schlüssel in einem PHP-Array? ?:

El Schlüssel kann entweder ein Ganzzahl oder eine String .

Das bedeutet, dass es 3 mögliche Fälle gibt:

  • Fall 1. alle Schlüssel sind numerisch / Ganzzahlen .
  • Fall 2. alle Schlüssel sind Zeichenketten .
  • Fall 3. Einige Schlüssel sind Zeichenketten sind einige Schlüssel numerisch / Ganzzahlen .

Wir können jeden Fall mit den folgenden Funktionen überprüfen.

Fall 1: Alle Schlüssel sind numerisch / Ganzzahlen .

Hinweis : Diese Funktion gibt zurück wahr auch für leere Arrays.

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

Fall 2: Alle Schlüssel sind Zeichenketten .

Hinweis : Diese Funktion gibt zurück wahr auch für leere Arrays.

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

Fall 3. Einige Schlüssel sind Zeichenketten sind einige Schlüssel numerisch / Ganzzahlen .

Hinweis : Diese Funktion gibt zurück wahr auch für leere Arrays.

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

Daraus folgt, dass:


Damit ein Array zu einem "echte" Reihe an die wir uns alle gewöhnt haben, das heißt:

  • Seine Tasten sind alle numerisch / Ganzzahlen .
  • Seine Schlüssel sind sequenziell (d. h. Erhöhung um Stufe 1).
  • Seine Tasten bei Null anfangen .

Wir können dies mit der folgenden Funktion überprüfen.

Fall 3a. Tasten sind numerisch / Ganzzahlen , sequenziell y Null-Basis .

Hinweis : Diese Funktion gibt zurück wahr auch für leere Arrays.

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

Caveats / Pitfalls (oder noch mehr seltsame Fakten über Array-Schlüssel in PHP)

Ganzzahlige Schlüssel

Die Schlüssel für diese Arrays sind Ganzzahlen :

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

String-Tasten

Die Schlüssel für diese Arrays sind Zeichenketten :

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øvrflöw' => "b");                    // Strings may contain all kinds of symbols.
array("functon" => "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!

Ganzzahlige Schlüssel, die wie Zeichenketten aussehen

Wenn Sie glauben, dass der Schlüssel in array("13" => "b") est un String , Sie sind falsch . Aus dem Dokument aquí :

Zeichenketten, die gültige Ganzzahlen enthalten, werden in den Typ Ganzzahl umgewandelt. So wird z. B. der Schlüssel "8" tatsächlich unter 8 gespeichert. Andererseits wird "08" nicht umgewandelt, da es sich nicht um eine gültige Dezimalzahl handelt.

Die Schlüssel für diese Arrays sind zum Beispiel Ganzzahlen :

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

Der Schlüssel für diese Arrays sind jedoch Zeichenketten :

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.

Darüber hinaus ist nach Angaben der doc ,

Die Größe einer ganzen Zahl ist plattformabhängig, obwohl ein Maximalwert von etwa zwei Milliarden der übliche Wert ist (das sind 32 Bits mit Vorzeichen). Bei 64-Bit-Plattformen liegt der Höchstwert normalerweise bei etwa 9E18, außer bei Windows, das immer 32 Bit hat. PHP unterstützt keine vorzeichenlosen Ganzzahlen.

Der Schlüssel für dieses Array ist also kann, muss aber nicht ein sein Ganzzahl - das hängt von Ihrer Plattform ab.

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

Noch schlimmer ist, dass PHP dazu neigt Buggy wenn die ganze Zahl in der Nähe der 2 liegt 31 \= 2.147.483.648 Grenze (siehe Wanze 51430 , Wanze 52899 ). Zum Beispiel in meiner lokalen Umgebung (PHP 5.3.8 auf XAMPP 1.7.7 auf Windows 7), var_dump(array("2147483647" => "b")) gibt

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

sondern auf diese Live-Demo auf Codepad (PHP 5.2.5), ergibt derselbe Ausdruck

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

Der Schlüssel ist also ein Ganzzahl in einer Umgebung, sondern eine String in einem anderen, auch wenn 2147483647 ist eine gültige vorzeichenbehaftete 32-Bit Ganzzahl .

2 Stimmen

Wie ich weiter unten erwähne, ist es jedoch erforderlich, ein Duplikat des zu prüfenden Arrays zu erstellen, was bei großen Arrays sehr kostspielig ist und auf gemeinsam genutzten Hosts eine potenzielle Quelle für Abstürze wegen Speichermangels darstellt.

0 Stimmen

Ich bin erstaunt, dass man "-13" in eine Zeichenkette umwandeln kann, aber nicht "+13". Ich denke, niemand würde "+13" statt "13" schreiben, aber es ist immer noch etwas seltsam

37voto

Alix Axel Punkte 146320

Geschwindigkeitstechnisch:

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

Speichertechnisch:

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

0 Stimmen

Das folgende Array: array(02=>11,1,2,456); wird mit dem obigen Algorithmus als nicht numerische Schlüssel angezeigt, auch wenn 02===2

29voto

Das ist der effizienteste Weg:

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

Das funktioniert, weil es die Schlüssel (die bei einem sequentiellen Array immer 0, 1, 2 usw. sind) mit den Schlüsseln der Schlüssel (die immer 0,1,2 usw. sein).

Laravel verwenden dieser Ansatz .

1 Stimmen

Clever, aber nicht gut. Warum ist dies "am effizientesten"? Es wäre viel lesbarer, einfach die array_keys($a) mit range(0, count($a)) zu vergleichen. Die cleverste Lösung ist meiner Erfahrung nach selten die beste. Vor allem, wenn die clevere Lösung buchstäblich keinen Mehrwert gegenüber der offensichtlichen und sauberen Alternative bietet.

5 Stimmen

Diese Funktion gibt zurück true para array(1=>"a") sondern false para array("a"=>"a") . Es wäre sinnvoller, wenn != wird ersetzt durch !== .

3 Stimmen

@Pang Sie haben Recht. Ich dachte zuerst, dass Ihr Kommentar sicher falsch sein muss, aber zu meiner Überraschung, [0] == ['a'] in PHP (seit 0 == 'a' und in der Tat, 0 == 'banana' ). PHPs == Der Betreiber ist wahnsinnig.

23voto

dsims Punkte 149
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}

2 Stimmen

Dies ist die seulement Antwort (zum Zeitpunkt meines Kommentars), die auf Folgendes eingehen kann: $array = array(0=>'blah', 2=>'yep', 3=>'wahey')

0 Stimmen

Sondern array('1'=>'asdf', '2'=>'too') wird als assoziatives Array betrachtet, obwohl es das nicht ist (die Schlüssel sind tatsächlich Strings)

1 Stimmen

@CaptainkurO Sie meinen numerisch. Es ist ein assoziatives Array.

18voto

podperson Punkte 2186

Ich habe beides verwendet array_keys($obj) !== range(0, count($obj) - 1) y array_values($arr) !== $arr (die sich gegenseitig verdoppeln, wobei der zweite billiger ist als der erste), aber beide versagen bei sehr großen Arrays.

Der Grund dafür ist array_keys y array_values sind beides sehr kostspielige Operationen (da sie ein völlig neues Array aufbauen, dessen Größe ungefähr der des Originals entspricht).

Die folgende Funktion ist robuster als die oben genannten Methoden:

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

Beachten Sie auch, dass Sie, wenn Sie sich nicht darum kümmern, Sparse Arrays von assoziativen Arrays zu unterscheiden, einfach zurückgeben können 'assoc' von beiden if Blöcke.

Abschließend sei gesagt, dass diese Methode zwar weniger "elegant" erscheint als viele der "Lösungen" auf dieser Seite, in der Praxis aber wesentlich effizienter ist. Fast jedes assoziative Array wird sofort erkannt. Nur indizierte Arrays werden erschöpfend geprüft, und die oben beschriebenen Methoden prüfen indizierte Arrays nicht nur erschöpfend, sie duplizieren sie.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X