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

775voto

Greg Punkte 306033

Sie haben zwei Fragen gestellt, die nicht ganz gleichwertig sind:

  • Erstens: Wie kann man feststellen, ob ein Array nur numerische Schlüssel hat?
  • Zweitens: Wie kann man feststellen, ob ein Array über sequenziell numerische Tasten, beginnend bei 0

Überlegen Sie, welche dieser Verhaltensweisen Sie tatsächlich brauchen. (Es kann sein, dass beide für Ihre Zwecke ausreichen.)

Die erste Frage (bei der einfach geprüft wird, ob alle Tasten numerisch sind) lautet gut beantwortet von Captain kurO .

Für die zweite Frage (Prüfung, ob das Array null-indiziert und sequentiell ist) können Sie die folgende Funktion verwenden:

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

41 Stimmen

Eine sehr elegante Lösung. Beachten Sie, dass sie im (zweideutigen) Fall eines leeren Arrays TRUE zurückgibt.

37 Stimmen

Ich denke, es ist sinnvoller, sequenzielle Arrays als einen Spezialfall von assoziativen Arrays zu betrachten. Jedes Array ist also assoziativ, aber nur einige sind sequentiell. Daher kann eine Funktion isSequential() würde mehr Sinn machen als isAssoc() . In einer solchen Funktion wird das leere Feld devrait als sequenziell angesehen werden. Die Formel könnte lauten array() === $arr || !isAssoc($arr) .

24 Stimmen

Ich denke, dies würde eine Menge potenzielle CPU-Zeit und Speicher vermeiden, wenn man prüfen würde, ob isset($arr[0]) falsch ist, bevor alle Schlüssel extrahiert werden, da es eindeutig assoziativ ist, wenn das Array nicht leer ist, aber kein Element an der Position 0 hat. Da "die meisten" echten assoziativen Arrays Strings als Schlüssel haben, sollte dies eine nette Optimierung für den allgemeinen Fall einer solchen Funktion sein.

488voto

Captain kurO Punkte 709

Um lediglich zu prüfen, ob das Array nicht-ganzzahlige Schlüssel hat (nicht, ob das Array sequentiell indiziert oder null-indiziert ist):

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

Wenn es mindestens einen String-Schlüssel gibt, $array wird als assoziatives Array betrachtet.

27 Stimmen

Diese Methode ist viel besser, als es scheint. Wenn count(filtered_array) == count(original_array), dann ist es ein assoc array. Wenn count(filtered_array) == 0, dann handelt es sich um ein indiziertes Array. Wenn count(filtered_array) < count(original_array), dann hat das Array sowohl numerische als auch String-Schlüssel.

0 Stimmen

Viel zu langsam. Dies wird iterieren und eine Funktion anwenden. Schauen Sie unten nach schnelleren Alternativen oder prüfen Sie einfach den ersten Schlüssel auf int.

1 Stimmen

Dies ergibt false für ["1" => "foo", 2, 3]. Gibt es wirklich keine Möglichkeit zu prüfen, ob ein Schlüssel ursprünglich als String definiert wurde? PHP scheint in einer Array-Definition alles in einen int zu verwandeln, wenn es kann. Brutal.

148voto

Dave Marshall Punkte 7177

Dies ist sicherlich eine bessere Alternative.

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

55 Stimmen

Dadurch werden die Werte im Array dupliziert, was potenziell sehr teuer ist. Sie sind viel besser dran, wenn Sie die Array-Schlüssel untersuchen.

0 Stimmen

Wenn einer der Array-Werte nicht gesetzt ist, liefert dieser Code kein gültiges Ergebnis mehr (z. B. unset($arr[0]); $isIndexed = array_values($arr) === $arr; // liefert false.)

0 Stimmen

Bitte schauen Sie sich meine Antwort unten an, die zwar kein prägnanter One-Liner ist, aber für große Arrays funktioniert.

79voto

squirrel Punkte 1960

Viele Kommentatoren in dieser Frage verstehen nicht, wie Arrays in PHP funktionieren. Von der Array-Dokumentation :

Ein Schlüssel kann entweder eine Ganzzahl oder eine Zeichenkette sein. Handelt es sich bei einem Schlüssel um die Standarddarstellung einer ganzen Zahl, wird er als solche interpretiert (d. h. "8" wird als 8 interpretiert, während "08" als "08" interpretiert wird). Fließkommazahlen in key werden auf Ganzzahl abgeschnitten. Die indizierten und assoziativen Array-Typen sind in PHP derselbe Typ, der sowohl Integer- als auch String-Indizes enthalten kann.

Mit anderen Worten, es gibt keinen Array-Schlüssel "8", weil er immer (stillschweigend) in die Ganzzahl 8 umgewandelt wird. Der Versuch, zwischen ganzen Zahlen und numerischen Zeichenfolgen zu unterscheiden, ist also unnötig.

Wenn Sie den effizientesten Weg suchen, um ein Array auf nicht-ganzzahlige Schlüssel zu überprüfen, ohne eine Kopie eines Teils des Arrays (wie array_keys()) oder des gesamten Arrays (wie foreach) zu erstellen:

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

Dies funktioniert, weil key() NULL zurückgibt, wenn die aktuelle Array-Position ungültig ist und NULL niemals ein gültiger Schlüssel sein kann (wenn Sie versuchen, NULL als Array-Schlüssel zu verwenden, wird es stillschweigend in "" umgewandelt).

0 Stimmen

Dies funktioniert nicht für nicht-sequenzielle Integer-Schlüssel. Versuchen Sie es mit [2 => 'a', 4 => 'b'].

2 Stimmen

@DavidJ, Was meinen Sie mit "funktioniert nicht"? Es wird erfolgreich festgestellt, dass alle Schlüssel Ganzzahlen sind. Behaupten Sie, dass ein Array wie das, das Sie gepostet haben, nicht als "numerisches Array" betrachtet werden sollte?

7 Stimmen

Ein nicht-assoziatives Array muss Schlüssel haben, die von 0 a count($array)-1 und zwar in dieser strengen Reihenfolge. Eine vorläufige Prüfung mit is_array() kann helfen. Fügen Sie eine steigende Variable hinzu, um die Tastenfolge zu überprüfen: for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k; Damit ist die Sache erledigt.

51voto

PHP 8.1 fügt eine eingebaute Funktion hinzu, um festzustellen, ob ein Array eine Liste mit dieser Semantik ist oder nicht. Die Funktion lautet array_is_list :

$list = ["a", "b", "c"];

array_is_list($list); // true

$notAList = [1 => "a", 2 => "b", 3 => "c"];

array_is_list($notAList); // false

$alsoNotAList = ["a" => "a", "b" => "b", "c" => "c"];

array_is_list($alsoNotAList); // false

Referenz

4 Stimmen

Danke für den Hinweis auf die native Lösung! Sie könnten hinzufügen, dass es auch ein Polyfill in packagist.org/packages/symfony/polyfill-php81 Damit sollte dieses Problem ein für alle Mal für alle, die PHP 7.1 und höher verwenden, gelöst sein. Verwenden Sie einfach symfony/polyfill-php81, das von composer bereitgestellt wird.

0 Stimmen

Es ist eine Schande, dass diese Antwort nie an die Spitze gelangen wird.

0 Stimmen

Habt Vertrauen. Stack Overflow wird bald seinen Trending-Sortieralgorithmus einführen und es wird einfacher sein, bemerkt zu werden.

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