PHP behandelt alle Arrays als assoziativ, daher sind keine Funktionen integriert. Kann jemand eine ziemlich effiziente Methode empfehlen, um zu überprüfen, ob ein Array nur numerische Schlüssel enthält?
Grundsätzlich möchte ich in der Lage sein, Folgendes zu unterscheiden:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
und das:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, was einfach und schnell ist. Natürlich sollten Sie zuerst sicherstellen, dass das Array nicht leer ist, und Sie sollten einige Kenntnisse über den möglichen Inhalt des Arrays haben, damit die Methode nicht fehlschlagen kann (wie gemischte numerische / assoziative oder nicht sequentielle).Antworten:
Sie haben zwei Fragen gestellt, die nicht ganz gleichwertig sind:
Überlegen Sie, welches dieser Verhaltensweisen Sie tatsächlich benötigen. (Es kann sein, dass beides für Ihre Zwecke ausreicht.)
Die erste Frage (einfach überprüfen, ob alle Schlüssel numerisch sind) wird von Captain KurO gut beantwortet .
Für die zweite Frage (Überprüfen, ob das Array nullindiziert und sequentiell ist) können Sie die folgende Funktion verwenden:
quelle
isSequential()
wäre eine Funktion sinnvoller alsisAssoc()
. In eine solche Funktion, die leere Array sollte als sequenzielle gesehen werden. Die Formel könnte seinarray() === $arr || !isAssoc($arr)
.array_key_exists
anstelle von verwendet werden,isset
da das isset falsch false zurückgibt, wenn das Nullelement ein Nullwert ist. Ein Nullwert sollte normalerweise ein legitimer Wert in einem solchen Array sein.So überprüfen Sie lediglich, ob das Array nicht ganzzahlige Schlüssel enthält (nicht, ob das Array sequenziell oder nullindiziert ist):
Wenn mindestens ein Zeichenfolgenschlüssel vorhanden ist,
$array
wird dies als assoziatives Array betrachtet.quelle
$isIndexed = array_values($arr) === $arr;
? Zu dem frage ich: Wie denkst duarray_values()
funktioniert das? Wie funktioniert Ihrer Meinung nach die===
Anwendung auf Arrays? Die Antwort ist natürlich, dass sie auch über das Array iterieren.var_dump([1.2 => 'foo', 1.5 => 'bar']);
Sie feststellen, dass Sie das Array erhalten[1 => 'bar']
. Es gibt überhaupt keine Möglichkeit, den Originaltyp eines Schlüssels herauszufinden. Ja, das alles ist schrecklich; PHPs Arrays sind bei weitem der schlechteste Teil der Sprache, und der größte Teil des Schadens ist irreparabel und beruht auf der Idee, ein einziges Konstrukt für traditionelle Arrays zu verwenden, und traditionelle Hashmaps sind von Anfang an schrecklich.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
wirdfalse
(sequentielles Array), während es sein solltetrue
(assoziatives Array). toolsqa.com/data-structures/array-in-programming Ich bin mir nicht sicher, ob der Schlüssel in aufsteigender Reihenfolge sein muss. (0, 1, ...)Dies ist sicherlich eine bessere Alternative.
quelle
===
damit verschwendet wird, zu überprüfen, ob die Werte gleich sind, obwohl wir nur an den Schlüsseln interessiert sind. Aus diesem Grund bevorzuge ich die$k = array_keys( $arr ); return $k === array_keys( $k );
Version.Viele Kommentatoren in dieser Frage verstehen nicht, wie Arrays in PHP funktionieren. Aus der Array-Dokumentation :
Mit anderen Worten, es gibt keinen Array-Schlüssel von "8", da er immer (stillschweigend) in die Ganzzahl 8 konvertiert wird. Daher ist es nicht erforderlich, zwischen Ganzzahlen und numerischen Zeichenfolgen zu unterscheiden.
Wenn Sie die effizienteste Methode zum Überprüfen eines Arrays auf nicht ganzzahlige Schlüssel suchen, ohne eine Kopie eines Teils des Arrays (wie bei array_keys ()) oder des gesamten Arrays (wie bei foreach) zu erstellen:
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 "" konvertiert).
quelle
0
biscount($array)-1
in dieser strengen Reihenfolge haben. Eine vorläufige Überprüfung mitis_array()
kann helfen. Fügen Sie eine zunehmende Variable hinzu, um die Tastenfolge zu überprüfen: Damit istfor ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
das Geschäft abgeschlossen.foreach
anstelle der expliziten Iteration ist etwa doppelt so schnell.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Wie vom OP angegeben :
Es ist nicht ganz sinnvoll (IMHO), eine Funktion zu schreiben, die prüft, ob ein Array assoziativ ist . Also als erstes: Was ist ein Schlüssel in einem PHP-Array ?
Das heißt, es gibt 3 mögliche Fälle:
Wir können jeden Fall mit den folgenden Funktionen überprüfen.
Fall 1: Alle Schlüssel sind numerisch / ganzzahlig .
Hinweis : Diese Funktion gibt auch für leere Arrays true zurück .
Fall 2: Alle Schlüssel sind Zeichenfolgen .
Hinweis : Diese Funktion gibt auch für leere Arrays true zurück .
Fall 3. Einige Schlüssel sind Zeichenfolgen , einige Schlüssel sind numerische / ganze Zahlen .
Hinweis : Diese Funktion gibt auch für leere Arrays true zurück .
Es folgt dem:
(was per Definition der Fall ist, wie in " Die leere Menge ist eine Teilmenge einer beliebigen Menge A, da alle ihre Elemente zu A gehören ").
Nun, damit ein Array ein "echtes" Array ist , an das wir alle gewöhnt sind, was bedeutet:
Wir können mit der folgenden Funktion überprüfen.
Fall 3a. Schlüssel sind numerisch / ganzzahlig , sequentiell und nullbasiert .
Hinweis : Diese Funktion gibt auch für leere Arrays true zurück .
Vorsichtsmaßnahmen / Fallstricke (oder noch eigentümlichere Fakten zu Array-Schlüsseln in PHP)
Ganzzahlige Schlüssel
Die Schlüssel für diese Arrays sind Ganzzahlen :
String-Schlüssel
Die Schlüssel für diese Arrays sind Zeichenfolgen :
Ganzzahlige Schlüssel, die wie Zeichenfolgen aussehen
Wenn Sie glauben, dass der Schlüssel
array("13" => "b")
eine Zeichenfolge ist , liegen Sie falsch . Aus dem Dokument hier :Der Schlüssel für diese Arrays sind beispielsweise Ganzzahlen :
Der Schlüssel für diese Arrays sind jedoch Zeichenfolgen :
Was mehr ist, laut dem Dokument ,
Der Schlüssel für dieses Array kann also eine Ganzzahl sein oder auch nicht - dies hängt von Ihrer Plattform ab.
Noch schlimmer ist , neigt dazu , PHP zu sein Buggy , wenn die ganzen Zahl in der Nähe der 2 31 = 2147483648 Grenze (siehe Bug 51430 , bug 52899 ). Zum Beispiel in meiner lokalen Umgebung (PHP 5.3.8 unter XAMPP 1.7.7 unter Windows 7)
var_dump(array("2147483647" => "b"))
gibtIn dieser Live-Demo auf dem Codepad (PHP 5.2.5) gibt es jedoch den gleichen Ausdruck
Der Schlüssel ist also eine Ganzzahl in einer Umgebung, aber eine Zeichenfolge in einer anderen, obwohl
2147483647
es sich um eine gültige vorzeichenbehaftete 32-Bit- Ganzzahl handelt .quelle
In Bezug auf die Geschwindigkeit:
In Bezug auf das Gedächtnis:
quelle
quelle
array('1'=>'asdf', '2'=>'too')
wird als assoziatives Array angesehen werden , während es eigentlich nicht (die Tasten sind eigentlich string)true
wenn die Schlüssel Null sind, Ganzzahlen (nur positiv), eine leere Zeichenfolge oder eine beliebige Kombination der oben genannten, z. B. die Zeichenfolge "09". Diese Funktion berücksichtigt nicht die Reihenfolge der Schlüssel. Alsoarray(0=>'blah', 2=>'yep', 3=>'wahey')
,array(0=>'blah', 2=>'yep', 1=>'wahey')
undarray('blah', 'yep', 'wahey')
sind alle gemäß dieser Funktion assoziativ, während diesarray('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')
nicht der Fall ist.Eigentlich ist der effizienteste Weg also:
Dies funktioniert, weil die Schlüssel (die für ein sequentielles Array immer 0,1,2 usw. sind) mit den Schlüsseln der Schlüssel (die immer 0,1,2 usw. sind) verglichen werden.
quelle
true
fürarray(1=>"a")
aberfalse
für zurückarray("a"=>"a")
. Wäre sinnvoller, wenn!=
durch ersetzt wird!==
.[0] == ['a']
in PHP (seit0 == 'a'
und in der Tat0 == 'banana'
). Der==
Betreiber von PHP ist verrückt.Ich habe beide
array_keys($obj) !== range(0, count($obj) - 1)
undarray_values($arr) !== $arr
(die Duals voneinander sind, obwohl die zweite billiger als die erste ist) verwendet, aber beide scheitern bei sehr großen Arrays.Dies liegt daran ,
array_keys
undarray_values
sind beide sehr teuer Operationen (da sie eine ganz neue Reihe von Größe in etwa die den ursprünglichen bauen).Die folgende Funktion ist robuster als die oben angegebenen Methoden:
Beachten Sie auch, dass Sie einfach
'assoc'
von beidenif
Blöcken zurückkehren können, wenn Sie keine spärlichen Arrays von assoziativen Arrays unterscheiden möchten .Während dies auf dieser Seite weniger "elegant" erscheint als viele "Lösungen", ist es in der Praxis weitaus effizienter. Fast jedes assoziative Array wird sofort erkannt. Nur indizierte Arrays werden ausführlich geprüft, und die oben beschriebenen Methoden prüfen indizierte Arrays nicht nur ausführlich, sondern duplizieren sie auch.
quelle
Ich denke, die folgenden zwei Funktionen sind der beste Weg, um zu überprüfen, ob ein Array assoziativ oder numerisch ist. Da 'numerisch' nur Zifferntasten oder nur sequentielle Zifferntasten bedeuten kann, sind nachfolgend zwei Funktionen aufgeführt, die beide Bedingungen überprüfen:
Die erste Funktion prüft, ob jeder Schlüssel ein ganzzahliger Wert ist. Die zweite Funktion prüft, ob jeder Schlüssel ein ganzzahliger Wert ist, und prüft außerdem, ob alle Schlüssel ab $ base sequentiell sind. Der Standardwert ist 0 und kann daher weggelassen werden, wenn Sie keinen anderen Basiswert angeben müssen. key ($ my_array) gibt null zurück, wenn der Lesezeiger über das Ende des Arrays hinausbewegt wird. Dies beendet die for-Schleife und macht die Anweisung nach der for-Schleife true, wenn alle Schlüssel ganzzahlig sind. Wenn nicht, endet die Schleife vorzeitig, da ein Schlüssel vom Typ string ist und die Anweisung nach der for-Schleife false zurückgibt. Die letztere Funktion addiert zusätzlich nach jedem Vergleich eine zu $ base, um zu überprüfen, ob der nächste Schlüssel den richtigen Wert hat. Durch den strengen Vergleich wird auch geprüft, ob der Schlüssel vom Typ Integer ist. Der $ base = (int) $ base-Teil im ersten Abschnitt der for-Schleife kann weggelassen werden, wenn $ base weggelassen wird oder wenn Sie sicherstellen, dass er nur mit einer Ganzzahl aufgerufen wird. Aber da ich nicht für alle sicher sein kann, habe ich es belassen. Die Anweisung wird sowieso nur einmal ausgeführt. Ich denke, das sind die effizientesten Lösungen:
Denken Sie daran, dass ein Array-Schlüssel nur eine Ganzzahl oder eine Zeichenfolge sein kann und eine streng numerische Zeichenfolge wie "1" (aber nicht "01") in eine Ganzzahl übersetzt wird. Aus diesem Grund ist die Suche nach einem Ganzzahlschlüssel neben dem Zählen die einzige erforderliche Operation, wenn das Array sequentiell sein soll. Wenn is_indexed_array false zurückgibt, kann das Array natürlich als assoziativ angesehen werden. Ich sage "gesehen", weil sie es tatsächlich alle sind.
quelle
Diese Funktion kann Folgendes verarbeiten:
Die Idee ist einfach: Wenn einer der Schlüssel KEINE Ganzzahl ist, handelt es sich um ein assoziatives Array, andernfalls handelt es sich um ein sequentielles Array.
quelle
Ich habe zwei beliebte Ansätze für diese Frage bemerkt: einen mit
array_values()
und einen mitkey()
. Um herauszufinden, was schneller ist, habe ich ein kleines Programm geschrieben:Die Ausgabe für das Programm unter PHP 5.2 unter CentOS lautet wie folgt:
Die Ausgabe von PHP 5.3 ergab ähnliche Ergebnisse. Offensichtlich ist die Verwendung
array_values()
viel schneller.quelle
$arrays = Array( 'Array #1' => range(0, 50000), );
Eine Möglichkeit, dies zu erreichen, ist das Huckepack-
json_encode
Verfahren, das bereits über eine eigene interne Methode zur Unterscheidung zwischen einem assoziativen Array und einem indizierten Array verfügt, um den richtigen JSON auszugeben.Sie können dies tun, indem Sie überprüfen, ob das erste nach der Codierung zurückgegebene Zeichen ein
{
(assoziatives Array) oder ein[
(indiziertes Array) ist.quelle
Es gibt bereits viele Antworten, aber hier ist die Methode, auf die sich Laravel in seiner Arr-Klasse stützt:
Quelle: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
quelle
array_keys($keys)
gibt ein sequentielles Array von Zahlen (0 ... X) zurück, das dieselbe Länge wie das ursprüngliche Array hat. Zum Beispielarray_keys(["a", "b", "c"]) = [0, 1, 2];
array_keys([0, 1, 2]) = [0, 1, 2]
(es ist ein sequentielles Array, weil[0, 1, 2] !== [0, 1, 2]
). Ein weiteres Beispiel:array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];
array_keys(["a", "b", "c"]) = [0, 1, 2]
(Es ist ein assoziatives Array, weil["a", "b", "c"] !== [0, 1, 2]
). Hoffe es ist klar (schwer ausführlich in einem Kommentar zu erklären, zumindest für mich)Schnell, präzise und speichereffizient. Keine teuren Vergleiche, Funktionsaufrufe oder Array-Kopien.
quelle
Mit der xarray PHP-Erweiterung
Sie können dies sehr schnell tun (ungefähr 30+ mal schneller in PHP 5.6):
Oder:
quelle
Ich weiß, dass es ein bisschen sinnlos ist, eine Antwort auf diese große Warteschlange hinzuzufügen, aber hier ist eine lesbare O (n) -Lösung, bei der keine Werte dupliziert werden müssen:
Anstatt die Schlüssel zu überprüfen, um festzustellen, ob sie alle numerisch sind, durchlaufen Sie die Schlüssel, die für ein numerisches Array vorhanden wären , und stellen sicher, dass sie vorhanden sind.
quelle
[1,2,null,4]
wird fehlschlagen, aber es ist korrektes Array. Also habe ich einige Verbesserungen unter stackoverflow.com/a/25206156/501831 mit Zusatzprüfung hinzugefügtarray_key_exists
)isset()
ist hier das falsche Werkzeug, da es falsenull
zurückgibt, wenn der Wert gesetzt ist , dies jedoch ist , wie von @lazycommit hervorgehoben.Meine Lösung:
array_merge
Auf einem einzelnen Array werden alleinteger
Schlüssel neu indiziert , andere jedoch nicht. Zum Beispiel:Wenn also eine Liste (ein nicht assoziatives Array) erstellt wird,
['a', 'b', 'c']
wird ein Wert entfernt undunset($a[1])
dannarray_merge
aufgerufen. Die Liste wird ab 0 neu indiziert.quelle
O(n)
in zusätzlichem Speicher verwendet (da mehrere neue Arrays mit so vielen Elementen wie erstellt wurden$array
). In der Antwort wird weder die Mehrdeutigkeit der gestellten Frage angesprochen noch genau erklärt, wie eine Liste / ein nicht assoziatives Array definiert wird, und sogar Wenn keiner dieser Punkte zutrifft, ist es unklar, dass dies im Vergleich zu anderen bereits veröffentlichten Antworten einen Mehrwert bringt.Nach einigem lokalen Benchmarking, Debugging, Compiler-Testen, Profiling und Missbrauch von 3v4l.org, um über mehrere Versionen hinweg Benchmarks zu erstellen (ja, ich habe eine Warnung zum Stoppen erhalten) und mit jeder Variation zu vergleichen, die ich finden konnte ...
Ich gebe Ihnen eine organisch abgeleitete assoziative Array-Testfunktion für das Best-Average-Worst-Case-Szenario , die im schlimmsten Fall ungefähr so gut oder besser ist als alle anderen Average-Case-Szenarien.
Von https://3v4l.org/rkieX :
quelle
Hier ist die Methode, die ich benutze:
Beachten Sie, dass dies keine Sonderfälle wie Folgendes berücksichtigt:
Entschuldigung, ich kann dir dabei nicht helfen. Es ist auch für Arrays mit anständiger Größe etwas performant, da es keine unnötigen Kopien erstellt. Es sind diese kleinen Dinge, die Python und Ruby so viel schöner machen, in ...: P.
quelle
Beide Beispiele, die die meisten Punkte erzielt haben, funktionieren mit Arrays wie nicht richtig
$array = array('foo' => 'bar', 1)
quelle
Dies würde auch funktionieren ( Demo ):
Bitte beachten Sie, dass der Hauptpunkt dieser Antwort darin besteht, Sie über die Existenz von zu informieren
SplFixedArray
und Sie nicht zu ermutigen, Ausnahmen für diese Art von Tests zu verwenden.quelle
Ich denke, die Definition eines skalaren Arrays variiert je nach Anwendung. Das heißt, einige Anwendungen erfordern ein strengeres Verständnis dessen, was als skalares Array qualifiziert ist, und einige Anwendungen erfordern ein lockereres Verständnis.
Im Folgenden stelle ich 3 Methoden unterschiedlicher Strenge vor.
quelle
Noch eine schnelle von der Quelle . Passen Sie die Codierung von
json_encode
(undbson_encode
) an. Dies gilt auch für die Konformität mit Javascript-Arrays.quelle
isset
undarray_key_exists
? würde letzteres nicht ausreichen?isset()
Prüfung hier ist völlig überflüssig.isset()
ist schneller alsarray_key_exists()
. siehe ilia.ws/archives/…null
s hat, aber es ist auch nicht so wahrscheinlich, dass Sie ein Array haben, das groß genug ist, dass es spürbare Leistungsunterschiede gibt mit beiden Schecksjson_encode
, können Sie einfach das erste Symbol der Zeichenfolge überprüfen, das vonjson_encode($your_arr)
- ob es ist[
oder{
;-)Könnte dies die Lösung sein?
Die Einschränkung ist offensichtlich, dass der Array-Cursor zurückgesetzt wird, aber ich würde sagen, dass die Funktion wahrscheinlich verwendet wird, bevor das Array überhaupt durchlaufen oder verwendet wird.
quelle
array("a", "b")
undarray("a", "b" => "B")
überprüft nur den ersten Schlüssel. Übrigensis_long
ist nur ein Alias vonis_int
.[7 => 'foo', 2 => 'bar']
beispielsweise als "gemischtes" Array klassifizieren, das teilweise, aber nicht "rein" sequentiell ist. Das scheint mir eine eindeutig falsche Verwendung von Wörtern zu sein.Viele der hier aufgeführten Lösungen sind elegant und hübsch, lassen sich jedoch nicht gut skalieren und sind speicher- oder CPU-intensiv. Die meisten erstellen mit dieser Lösung von beiden Seiten des Vergleichs zwei neue Datenpunkte im Speicher. Je größer das Array, desto schwieriger und länger werden der Prozess und der Speicher verwendet, und Sie verlieren den Vorteil einer Kurzschlussbewertung. Ich habe einige Tests mit verschiedenen Ideen durchgeführt. Es wird versucht, zu vermeiden, dass array_key_exists teuer ist, und es wird auch vermieden, neue große Datensätze zum Vergleichen zu erstellen. Ich denke, dies ist eine einfache Möglichkeit, um festzustellen, ob ein Array sequentiell ist.
Sie führen eine einzelne Zählung für das Hauptarray aus und speichern eine einzelne Ganzzahl. Anschließend durchlaufen Sie das Array und prüfen, ob eine genaue Übereinstimmung vorliegt, während Sie den Zähler durchlaufen. Sie sollten von 1 zu zählen haben. Wenn es fehlschlägt, wird es kurzgeschlossen, was zu einer Leistungssteigerung führt, wenn es falsch ist.
Ursprünglich habe ich dies mit einer for-Schleife gemacht und nach isset gesucht ($ arr [$ i]), aber dies erkennt keine Nullschlüssel, für die array_key_exists erforderlich ist, und wie wir wissen, ist dies die schlechteste Funktion für die Geschwindigkeit.
Durch die ständige Aktualisierung von Variablen über foreach, um zu überprüfen, ob der Iterator nie über seine ganzzahlige Größe hinaus wächst, kann PHP die integrierte Speicheroptimierung, das Caching und die Speicherbereinigung verwenden, um den Ressourcenverbrauch sehr gering zu halten.
Außerdem werde ich argumentieren, dass die Verwendung von array_keys in einem foreach dumm ist, wenn Sie einfach $ key => $ value ausführen und den Schlüssel überprüfen können. Warum den neuen Datenpunkt erstellen? Sobald Sie die Array-Schlüssel entfernt haben, haben Sie sofort mehr Speicher verbraucht.
quelle
Antworten sind bereits gegeben, aber es gibt zu viele Desinformationen über die Leistung. Ich habe dieses kleine Benchmark-Skript geschrieben, das zeigt, dass die foreach-Methode die schnellste ist.
Haftungsausschluss: Die folgenden Methoden wurden aus den anderen Antworten kopiert
Ergebnisse:
quelle
Oder Sie können einfach Folgendes verwenden:
Hiermit wird überprüft, ob das Array einen nicht numerischen Schlüssel enthält oder:
um zu überprüfen, ob das Array streng sequenziell ist (enthält automatisch generierte int-Schlüssel 0 bis n-1 )
mit dieser Bibliothek.
quelle
Wenn PHP nicht über eine integrierte Funktion verfügt, können Sie dies nicht in weniger als O (n) tun - indem Sie alle Schlüssel auflisten und nach dem Integer-Typ suchen. In der Tat möchten Sie auch sicherstellen, dass keine Löcher vorhanden sind, sodass Ihr Algorithmus möglicherweise folgendermaßen aussieht:
Aber warum sich die Mühe machen? Nehmen Sie einfach an, dass das Array vom erwarteten Typ ist. Wenn nicht, wird es nur in Ihrem Gesicht explodieren - das ist dynamische Programmierung für Sie! Testen Sie Ihren Code und alles wird gut ...
quelle
Ich vergleiche den Unterschied zwischen den Schlüsseln des Arrays und den Schlüsseln des Ergebnisses von array_values () des Arrays, das immer ein Array mit ganzzahligen Indizes sein wird. Wenn die Schlüssel identisch sind, handelt es sich nicht um ein assoziatives Array.
quelle
O(n)
zusätzlichen Speicher , wenn$array
hatn
Elemente, und das Schreiben(someboolean) ? false : true
statt!someboolean
ist schrecklich und es wirklich ausführlich.