PHP traite tous les tableaux comme associatifs, il n'y a donc aucune fonction intégrée. Quelqu'un peut-il recommander un moyen assez efficace de vérifier si un tableau ne contient que des clés numériques?
Fondamentalement, je veux pouvoir faire la différence entre ceci:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
et ça:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, ce qui est simple et rapide. Bien sûr, vous devez d'abord vous assurer que le tableau n'est pas vide, et vous devez avoir une certaine connaissance du contenu possible du tableau afin que la méthode ne puisse pas échouer (comme mixte numérique / associatif ou non séquentiel).Réponses:
Vous avez posé deux questions qui ne sont pas tout à fait équivalentes:
Considérez lequel de ces comportements vous avez réellement besoin. (Il se peut que l'un ou l'autre fasse l'affaire pour vous.)
La première question (vérifier simplement que toutes les touches sont numériques) est bien répondu par le capitaine kurO .
Pour la deuxième question (vérifier si le tableau est indexé zéro et séquentiel), vous pouvez utiliser la fonction suivante:
la source
isSequential()
aurait plus de sens queisAssoc()
. Dans une telle fonction, le tableau vide doit être considéré comme séquentiel. La formule pourrait êtrearray() === $arr || !isAssoc($arr)
.array_key_exists
au lieu deisset
parce que si l'élément zéro est une valeur nulle, le isset retournera faux incorrectement. Une valeur nulle doit normalement être une valeur légitime dans un tel tableau.Pour vérifier simplement si le tableau a des clés non entières (pas si le tableau est indexé séquentiellement ou zéro):
S'il y a au moins une clé de chaîne,
$array
sera considérée comme un tableau associatif.la source
$isIndexed = array_values($arr) === $arr;
? À quoi je demande: comment pensez-vous que celaarray_values()
fonctionne? Comment pensez-vous que l'===
application aux tableaux fonctionne? La réponse est bien sûr qu'ils parcourent également le tableau.var_dump([1.2 => 'foo', 1.5 => 'bar']);
vous découvrirez que vous obtenez le tableau[1 => 'bar']
. Il n'y a aucun moyen de découvrir le type d'origine d'une clé. Oui, tout cela est affreux; Les tableaux de PHP sont de loin la pire partie du langage, et la plupart des dommages sont irréparables et doivent à l'idée d'utiliser une seule construction pour les tableaux traditionnels et les hashmaps traditionnels étant horribles dès le début.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
deviendrafalse
(tableau séquentiel) alors qu'il devrait l'êtretrue
(tableau associatif). toolsqa.com/data-structures/array-in-programming Je ne suis pas sûr que la clé soit dans l'ordre croissant? (0, 1, ...)C'est sûrement une meilleure alternative.
la source
===
perdrez du temps à vérifier si les valeurs sont égales, même si nous ne nous intéressons qu'aux clés. Pour cette raison, je préfère la$k = array_keys( $arr ); return $k === array_keys( $k );
version.De nombreux commentateurs dans cette question ne comprennent pas comment fonctionnent les tableaux en PHP. Dans la documentation de la baie :
En d'autres termes, il n'existe pas de clé de tableau de "8" car elle sera toujours (silencieusement) convertie en entier 8. Il n'est donc pas nécessaire d'essayer de différencier les entiers des chaînes numériques.
Si vous voulez le moyen le plus efficace de vérifier un tableau pour les clés non entières sans faire une copie d'une partie du tableau (comme le fait array_keys ()) ou de tout (comme foreach le fait):
Cela fonctionne car key () renvoie NULL lorsque la position actuelle du tableau n'est pas valide et NULL ne peut jamais être une clé valide (si vous essayez d'utiliser NULL comme clé de tableau, elle est silencieusement convertie en "").
la source
0
àcount($array)-1
, dans cet ordre strict. Une vérification préliminaire avecis_array()
peut aider. Ajoutez une variable croissante pour vérifier la séquence de touches:for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
cela règle l'accord.foreach
au lieu d'une itération explicite est environ deux fois plus rapide.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Comme indiqué par le PO :
il n'est pas tout à fait sensé (à mon humble avis) d'écrire une fonction qui vérifie si un tableau est associatif . Donc, première chose: qu'est-ce qu'une clé dans un tableau PHP ?:
Cela signifie qu'il y a 3 cas possibles:
Nous pouvons vérifier chaque cas avec les fonctions suivantes.
Cas 1: toutes les clés sont numériques / entières .
Remarque : Cette fonction renvoie également true pour les tableaux vides.
Cas 2: toutes les clés sont des chaînes .
Remarque : Cette fonction renvoie également true pour les tableaux vides.
Cas 3. certaines clés sont des chaînes , certaines clés sont numériques / entières .
Remarque : Cette fonction renvoie également true pour les tableaux vides.
Il s'ensuit que:
(ce qui est par définition, comme dans " l'ensemble vide est un sous-ensemble de tout ensemble A car tous ses éléments appartiennent à A ").
Maintenant, pour qu'un tableau soit un tableau "authentique" auquel nous sommes tous habitués, ce qui signifie:
Nous pouvons vérifier avec la fonction suivante.
Cas 3a. les clés sont numériques / entières , séquentielles et basées sur zéro .
Remarque : Cette fonction renvoie également true pour les tableaux vides.
Avertissements / pièges (ou, encore plus de faits particuliers sur les clés de tableau en PHP)
Touches entières
Les clés de ces tableaux sont des entiers :
Touches de chaîne
Les clés de ces tableaux sont des chaînes :
Touches entières qui ressemblent à des chaînes
Si vous pensez que la clé
array("13" => "b")
est une chaîne , vous vous trompez . Du doc ici :Par exemple, la clé de ces tableaux sont des entiers :
Mais la clé de ces tableaux sont des chaînes :
De plus, selon le doc ,
La clé de ce tableau peut donc être ou non un entier - cela dépend de votre plate-forme.
Pire encore, PHP a tendance à être bogué si l'entier est proche de la frontière 2 31 = 2 147 483 648 (voir bogue 51430 , bogue 52899 ). Par exemple, sur mon environnement local (PHP 5.3.8 sur XAMPP 1.7.7 sur Windows 7),
var_dump(array("2147483647" => "b"))
donnemais sur cette démo en direct sur codepad (PHP 5.2.5), la même expression donne
La clé est donc un entier dans un environnement mais une chaîne dans un autre, même s'il
2147483647
s'agit d'un entier 32 bits signé valide .la source
En termes de vitesse:
Côté mémoire:
la source
la source
array('1'=>'asdf', '2'=>'too')
sera considéré comme un tableau associatif alors qu'il ne l'est pas réellement (les clés sont en fait des chaînes)true
si les clés sont: zéro, des nombres entiers (positifs uniquement), une chaîne vide ou toute combinaison des éléments ci-dessus, comme la chaîne "09". Cette fonction ne prend pas en compte l'ordre des clés. Doncarray(0=>'blah', 2=>'yep', 3=>'wahey')
,array(0=>'blah', 2=>'yep', 1=>'wahey')
etarray('blah', 'yep', 'wahey')
sont tous associatifs selon cette fonction, alors que cearray('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')
n'est pas le cas.En fait, le moyen le plus efficace est donc:
Cela fonctionne car il compare les clés (qui pour un tableau séquentiel sont toujours 0,1,2 etc.) aux clés des clés (qui seront toujours 0,1,2 etc.).
la source
true
pourarray(1=>"a")
maisfalse
pourarray("a"=>"a")
. Serait plus significatif s'il!=
est remplacé par!==
.[0] == ['a']
en PHP (depuis0 == 'a'
, et, en effet0 == 'banana'
). L'==
opérateur de PHP est fou.J'ai utilisé les deux
array_keys($obj) !== range(0, count($obj) - 1)
etarray_values($arr) !== $arr
(qui sont duaux l'un de l'autre, bien que le second soit moins cher que le premier) mais les deux échouent pour les très grands tableaux.En effet,
array_keys
etarray_values
sont toutes deux des opérations très coûteuses (car elles construisent un tout nouveau tableau de taille à peu près celui de l'original).La fonction suivante est plus robuste que les méthodes fournies ci-dessus:
Notez également que si vous ne vous souciez pas de différencier les tableaux clairsemés des tableaux associatifs, vous pouvez simplement revenir
'assoc'
des deuxif
blocs.Enfin, bien que cela puisse sembler beaucoup moins «élégant» que beaucoup de «solutions» sur cette page, en pratique, il est beaucoup plus efficace. Presque tous les tableaux associatifs seront détectés instantanément. Seuls les tableaux indexés seront vérifiés de manière exhaustive, et les méthodes décrites ci-dessus non seulement vérifient de manière exhaustive les tableaux indexés, mais les dupliquent.
la source
Je pense que les deux fonctions suivantes sont la meilleure façon de vérifier «si un tableau est associatif ou numérique». Étant donné que «numérique» peut signifier uniquement des touches numériques ou uniquement des touches numériques séquentielles, deux fonctions sont répertoriées ci-dessous qui vérifient l'une ou l'autre condition:
La première fonction vérifie si chaque clé est une valeur entière. La deuxième fonction vérifie si chaque clé est une valeur entière et vérifie en outre si toutes les clés sont séquentielles à partir de $ base, ce qui par défaut est 0 et peut donc être omis si vous n'avez pas besoin de spécifier une autre valeur de base. key ($ my_array) retourne null si le pointeur de lecture est déplacé au-delà de la fin du tableau, ce qui termine la boucle for et rend la déclaration après la boucle for vraie si toutes les clés sont entières. Sinon, la boucle se termine prématurément car une clé est de type chaîne et l'instruction après la boucle for renverra false. Cette dernière fonction ajoute en plus un à $ base après chaque comparaison, pour pouvoir vérifier si la clé suivante a la valeur correcte. La comparaison stricte permet également de vérifier si la clé est de type entier. La partie $ base = (int) $ base dans la première section de la boucle for peut être omise lorsque $ base est omis ou si vous vous assurez qu'elle n'est appelée qu'en utilisant un entier. Mais comme je ne peux pas être sûr pour tout le monde, je l'ai laissé. La déclaration n'est exécutée qu'une seule fois, de toute façon. Je pense que ce sont les solutions les plus efficaces:
N'oubliez pas qu'une clé de tableau ne peut être qu'un entier ou une chaîne et qu'une chaîne strictement numérique telle que "1" (mais pas "01") sera traduite en entier. C'est ce qui fait que la recherche d'une clé entière est la seule opération nécessaire en plus de compter si vous voulez que le tableau soit séquentiel. Naturellement, si is_indexed_array renvoie false, le tableau peut être considéré comme associatif. Je dis «vu», car en fait ils le sont tous.
la source
Cette fonction peut gérer:
l'idée est simple: si l'une des clés n'est PAS un entier, c'est un tableau associatif, sinon c'est séquentiel.
la source
J'ai remarqué deux approches populaires pour cette question: l'une utilisant
array_values()
et l'autre utilisantkey()
. Pour savoir ce qui est plus rapide, j'ai écrit un petit programme:La sortie du programme sur PHP 5.2 sur CentOS est la suivante:
La sortie sur PHP 5.3 a donné des résultats similaires. De toute évidence, l'utilisation
array_values()
est beaucoup plus rapide.la source
$arrays = Array( 'Array #1' => range(0, 50000), );
Une façon d'aborder cela est de se superposer
json_encode
, qui a déjà sa propre méthode interne de différenciation entre un tableau associatif et un tableau indexé afin de sortir le JSON correct.Vous pouvez le faire en vérifiant si le premier caractère renvoyé après l'encodage est un
{
(tableau associatif) ou un[
(tableau indexé).la source
Il existe déjà de nombreuses réponses, mais voici la méthode sur laquelle Laravel s'appuie dans sa classe Arr:
Source: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
la source
array_keys($keys)
renverra un tableau séquentiel de nombres (0 ... X) qui a la même longueur que le tableau d'origine. Par exemplearray_keys(["a", "b", "c"]) = [0, 1, 2];
array_keys([0, 1, 2]) = [0, 1, 2]
(c'est un tableau séquentiel parce que[0, 1, 2] !== [0, 1, 2]
). Un autre exemple:array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];
array_keys(["a", "b", "c"]) = [0, 1, 2]
(c'est un tableau associatif car["a", "b", "c"] !== [0, 1, 2]
). J'espère que c'est clair (difficile à expliquer en détail dans un commentaire, du moins pour moi)Rapide, concis et efficace en mémoire. Aucune comparaison coûteuse, appel de fonction ou copie de tableau.
la source
En utilisant l' extension PHP xarray
Vous pouvez le faire très rapidement (environ 30 fois plus vite en PHP 5.6):
Ou:
la source
Je sais qu'il est un peu inutile d'ajouter une réponse à cette énorme file d'attente, mais voici une solution O (n) lisible qui ne nécessite pas de duplication de valeurs:
Plutôt que de vérifier les clés pour voir si elles sont toutes numériques, vous parcourez les clés qui seraient là pour un tableau numérique et vous vous assurez qu'elles existent.
la source
[1,2,null,4]
échouera, mais c'est un tableau correct. j'ai donc ajouté des améliorations sur stackoverflow.com/a/25206156/501831 avecarray_key_exists
vérification de l' addition )isset()
est le mauvais outil ici car il retournera false si la valeur est définie mais l'estnull
, comme l'a souligné @lazycommit.Ma solution:
array_merge
sur un seul tableau réindexera toutes lesinteger
clés, mais pas les autres. Par exemple:Donc, si une liste (un tableau non associatif) est créée,
['a', 'b', 'c']
une valeur est suppriméeunset($a[1])
puisarray_merge
appelée, la liste est réindexée à partir de 0.la source
O(n)
dans la mémoire supplémentaire utilisée (car elle a créé plusieurs nouveaux tableaux avec autant d'éléments que$array
), la réponse ne répond pas à l'ambiguïté de la question qui a été posée ni n'explique exactement comment elle définit une liste / tableau non associatif, et même si aucun de ces points n'était vrai, il n'est pas clair que cela ajoute une valeur par rapport aux autres réponses déjà publiées.Après quelques analyses locales, débogage, vérification du compilateur, profilage et abus de 3v4l.org pour comparer plusieurs versions (oui, j'ai reçu un avertissement pour arrêter) et comparer avec chaque variation que j'ai pu trouver ...
Je vous donne une fonction de test associatif de tableau associatif du meilleur-moyen-pire-cas dérivée organiquement qui est au pire à peu près aussi bonne ou meilleure que tous les autres scénarios de cas moyen.
Depuis https://3v4l.org/rkieX :
la source
Voici la méthode que j'utilise:
Notez que cela ne tient pas compte des cas spéciaux comme:
Désolé, je ne peux pas vous aider. Il est également quelque peu performant pour les tableaux de taille décente, car il ne fait pas de copies inutiles. Ce sont ces petites choses qui rendent Python et Ruby tellement plus agréables à écrire ...: P
la source
Ces deux exemples, qui ont marqué le plus de points, ne fonctionnent pas correctement avec des tableaux comme
$array = array('foo' => 'bar', 1)
la source
Cela fonctionnerait aussi ( démo ):
Veuillez noter que le point principal de cette réponse est de vous informer de l'existence de
SplFixedArray
et non de vous encourager à utiliser des exceptions pour ce type de tests.la source
Je pense que la définition d'un tableau scalaire variera selon l'application. Autrement dit, certaines applications nécessiteront un sens plus strict de ce qui peut être qualifié de tableau scalaire, et certaines applications nécessiteront un sens plus lâche.
Ci-dessous, je présente 3 méthodes de rigueur variable.
la source
Un de plus rapide depuis la source . Ajuster l'encodage de
json_encode
(etbson_encode
). Il en va de même pour la conformité aux tableaux javascript.la source
isset
etarray_key_exists
? cette dernière ne suffirait-elle pas?isset()
vérification ici est complètement redondante.isset()
est plus rapide quearray_key_exists()
. voir ilia.ws/archives/…null
s, mais alors il est également peu probable que vous ayez un tableau assez grand pour qu'il y ait une différence de performance notable en utilisant les deux chèquesjson_encode
, vous pouvez simplement vérifier le premier symbole de la chaîne, renvoyé parjson_encode($your_arr)
- que ce soit[
ou{
;-)Serait-ce la solution?
La mise en garde est évidemment que le curseur du tableau est réinitialisé, mais je dirais que la fonction est probablement utilisée avant même que le tableau soit traversé ou utilisé.
la source
array("a", "b")
etarray("a", "b" => "B")
comme elle vérifie uniquement la première clé. BTW,is_long
est juste un alias deis_int
.[7 => 'foo', 2 => 'bar']
un tableau "mixte" qui est partiellement mais pas "purement" séquentiel. Cela me semble une utilisation manifestement incorrecte des mots.Beaucoup de solutions ici sont élégantes et jolies, mais ne s'adaptent pas bien et sont gourmandes en mémoire ou en processeur. La plupart créent 2 nouveaux points de données en mémoire avec cette solution des deux côtés de la comparaison. Plus la baie est grande, plus le processus et la mémoire utilisés sont longs et durs, et vous perdez l'avantage de l'évaluation des courts-circuits. J'ai fait quelques tests avec quelques idées différentes. Essayer d'éviter array_key_exists car il est coûteux, et éviter également de créer de nouveaux grands ensembles de données à comparer. Je pense que c'est un moyen simple de savoir si un tableau est séquentiel.
Vous exécutez un seul décompte sur le tableau principal et stockez un seul entier. Vous parcourez ensuite le tableau et vérifiez une correspondance exacte tout en itérant le compteur. Vous devriez avoir de 1 à compter. S'il échoue, il court-circuitera ce qui vous donnera une amélioration des performances lorsqu'il est faux.
À l'origine, je l'ai fait avec une boucle for et en vérifiant Isset ($ arr [$ i]) mais cela ne détectera pas les clés nulles qui nécessitent array_key_exists, et comme nous le savons, c'est la pire fonction à utiliser pour la vitesse.
Mettre à jour constamment les variables via foreach pour vérifier que l'itérateur ne dépasse jamais sa taille entière, PHP utilise son optimisation de mémoire intégrée, la mise en cache et la collecte des ordures pour vous garder à une utilisation des ressources très faible.
En outre, je soutiendrai que l'utilisation de array_keys dans un foreach est stupide lorsque vous pouvez simplement exécuter $ key => $ value et vérifier la clé. Pourquoi créer le nouveau point de données? Une fois que vous avez retiré les clés du tableau, vous avez immédiatement consommé plus de mémoire.
la source
les réponses sont déjà données mais il y a trop de désinformation sur les performances. J'ai écrit ce petit script de référence qui montre que la méthode foreach est la plus rapide.
Avertissement: les méthodes suivantes ont été copiées-collées à partir des autres réponses
résultats:
la source
Ou vous pouvez simplement utiliser ceci:
qui vérifiera si le tableau contient une clé non numérique ou:
pour vérifier si le tableau est strictement séquentiel (contient les clés int générées automatiquement 0 à n-1 )
en utilisant cette bibliothèque.
la source
À moins que PHP n'ait une fonction intégrée pour cela, vous ne pourrez pas le faire en moins de O (n) - en énumérant toutes les clés et en vérifiant le type entier. En fait, vous voulez également vous assurer qu'il n'y a pas de trous, donc votre algorithme pourrait ressembler à:
Mais pourquoi s'embêter? Supposez simplement que le tableau est du type que vous attendez. Si ce n'est pas le cas, cela vous explosera au visage - c'est une programmation dynamique pour vous! Testez votre code et tout ira bien ...
la source
Je compare la différence entre les clés du tableau et les clés du résultat de array_values () du tableau, qui sera toujours un tableau avec des indices entiers. Si les clés sont les mêmes, ce n'est pas un tableau associatif.
la source
O(n)
mémoire supplémentaire lorsqu'il$array
a desn
éléments, et l'écriture(someboolean) ? false : true
au lieu de!someboolean
est horrible et verbeuse gratuitement.