Comment vérifier si le tableau PHP est associatif ou séquentiel?

781

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');
Wilco
la source
382
Il y a un bug dans votre code: la tomate est un fruit.
Olle Härstedt
9
Cette méthode a des mises en garde, mais souvent je le fais 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).
Gras Double
@ OlleHärstedt Pas selon la Haute Cour des États-Unis. ;-)
MC Emperor

Réponses:

622

Vous avez posé deux questions qui ne sont pas tout à fait équivalentes:

  • Premièrement, comment déterminer si un tableau n'a que des touches numériques
  • Deuxièmement, comment déterminer si un tableau a des touches numériques séquentielles , à partir de 0

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:

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
Mark Amery
la source
32
Solution très élégante. Notez qu'il retourne TRUE dans le cas (ambigu) d'un tableau vide.
Jonathan Lidbeck
30
Je pense qu'il est plus utile de penser aux tableaux séquentiels comme un cas spécial de tableaux associatifs. Ainsi, chaque tableau est associatif, mais seuls certains sont séquentiels. Par conséquent, une fonction isSequential()aurait plus de sens que isAssoc(). Dans une telle fonction, le tableau vide doit être considéré comme séquentiel. La formule pourrait être array() === $arr || !isAssoc($arr).
donquixote
18
Je pense que cela éviterait beaucoup de temps de processeur potentiel et de mémoire si on vérifiait si isset ($ arr [0]) était faux avant d'extraire toutes les clés car il est clairement associatif si le tableau n'est pas vide mais n'a pas d'élément en 0 position. Comme «la plupart» des tableaux associatifs réels ont des chaînes comme clés, cela devrait être une bonne optimisation pour le cas général d'une telle fonction.
OderWat
10
@OderWat - Votre optimisation doit utiliser array_key_existsau lieu de issetparce 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.
OCDev
@MAChitgarha, votre modification a changé le comportement de la fonction sans expliquer pourquoi, et l'a fait contredire la description dans la prose ci-dessus de ce qu'elle est réellement censée faire. Je l'ai inversé.
Mark Amery
431

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

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

S'il y a au moins une clé de chaîne, $arraysera considérée comme un tableau associatif.

Captain kurO
la source
22
Cette méthode est bien meilleure qu'il n'y paraît. Si count (filter_array) == count (original_array), alors c'est un tableau associé. Si count (filter_array) == 0, alors c'est un tableau indexé. Si count (filter_array) <count (original_array), le tableau contient à la fois des clés numériques et des clés de chaîne.
Jamol
5
@MikePretzlaw, bien sûr, il itère; il n'y a (évidemment) aucun moyen possible de déterminer si toutes les clés du tableau sont des entiers sans regarder toutes les clés du tableau. Je suppose que les alternatives non itératives que nous sommes censés voir ci-dessous sont celles comme $isIndexed = array_values($arr) === $arr;? À quoi je demande: comment pensez-vous que cela array_values()fonctionne? Comment pensez-vous que l' ===application aux tableaux fonctionne? La réponse est bien sûr qu'ils parcourent également le tableau.
Mark Amery du
4
@ARW "PHP semble tout convertir en un int dans une définition de tableau s'il le peut." - oui, c'est exactement ce qui se passe. Le plus grand WTF est qu'il le fait même pour les flotteurs; si vous essayez, 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.
Mark Amery
30
@MarkAmery Ce qui précède, bien que simple, garantit une marche à 100% du tableau. Ce serait plus efficace, surtout si vous avez affaire à de grands tableaux, si vous recherchiez une chaîne ou un int et que vous avez éclaté le premier que vous avez trouvé. Par exemple: function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
Pensé le
1
@Thought Votre code fonctionne très rapidement mais il ne peut pas détecter de tableau séquentiel . L'exemple array(1 => 'a', 0 => 'b', 2 => 'c')deviendra false(tableau séquentiel) alors qu'il devrait l'être true(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, ...)
vee
132

C'est sûrement une meilleure alternative.

<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
Dave Marshall
la source
52
Cela va dupliquer les valeurs du tableau, ce qui est potentiellement très coûteux. Il vaut mieux examiner les clés du tableau.
meagar
8
Je viens d'utiliser ==; Je ne pense pas qu'il y ait un besoin pour === ici. Mais pour répondre au "non défini et cela ne fonctionne pas": une fois que vous avez désélectionné le premier élément, ce n'est plus un tableau indexé à partir de 0. Donc, OMI, cela fonctionne.
grantwparks
4
D'accord avec @grantwparks: un tableau clairsemé n'est pas indexé. Fait intéressant, car il n'y a aucun moyen de supprimer réellement un élément du milieu d'un tableau indexé. PHP déclare fondamentalement tous les tableaux comme associatifs et numériques est juste une version 'make up the key for me'.
RickMeasham
7
Le seul problème que j'ai avec cela, c'est que vous ===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.
Jesse
5
Une note supplémentaire, cela échoue sur les tableaux spécifiés avec des touches numériques qui sont hors service. par exemple $ myArr = array (0 => 'a', 3 => 'b', 4 => 1, 2 => 2, 1 => '3'); Une solution possible consiste à exécuter ksort ($ arr) avant de faire le test
Scott
77

De nombreux commentateurs dans cette question ne comprennent pas comment fonctionnent les tableaux en PHP. Dans la documentation de la baie :

Une clé peut être soit un entier soit une chaîne. Si une clé est la représentation standard d'un entier, elle sera interprétée comme telle (c'est-à-dire que "8" sera interprété comme 8, tandis que "08" sera interprété comme "08"). Les flottants dans la clé sont tronqués en entier. Les types de tableaux indexés et associatifs sont du même type en PHP, qui peuvent à la fois contenir des indices entiers et des chaînes.

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

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

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

écureuil
la source
Cela ne fonctionne pas pour les clés entières non séquentielles. Essayez-le avec [2 => 'a', 4 => 'b'].
DavidJ
2
@DavidJ, Qu'entendez-vous par «ne fonctionne pas»? Il détermine avec succès que toutes les clés sont des entiers. Êtes-vous en train de prétendre qu'un tableau comme celui que vous avez publié ne devrait pas être considéré comme un "tableau numérique"?
coredumperror
7
Un tableau non associatif doit avoir des clés allant de 0à count($array)-1, dans cet ordre strict. Une vérification préliminaire avec is_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.
ofavre
2
L'utilisation foreachau lieu d'une itération explicite est environ deux fois plus rapide.
ofavre
1
Si vous voulez en faire une fonction: function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
GreeKatrina
39

Comme indiqué par le PO :

PHP traite tous les tableaux comme associatifs

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 ?:

La clé peut être soit un entier soit une chaîne .

Cela signifie qu'il y a 3 cas possibles:

  • Cas 1. toutes les clés sont numériques / entières .
  • Cas 2. toutes les clés sont des chaînes .
  • Cas 3. certaines clés sont des chaînes , certaines clés sont numériques / entières .

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.

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

Cas 2: toutes les clés sont des chaînes .

Remarque : Cette fonction renvoie également true pour les tableaux vides.

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

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.

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

Il s'ensuit que:


Maintenant, pour qu'un tableau soit un tableau "authentique" auquel nous sommes tous habitués, ce qui signifie:

  • Ses clés sont toutes numériques / entières .
  • Ses clés sont séquentielles (c'est-à-dire augmentant à l'étape 1).
  • Ses clés partent de zéro .

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.

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

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 :

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

Touches de chaîne

Les clés de ces tableaux sont des chaînes :

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!

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 :

Les chaînes contenant des entiers valides seront converties en type entier. Par exemple, la clé "8" sera stockée sous 8. En revanche, "08" ne sera pas converti, car il ne s'agit pas d'un entier décimal valide.

Par exemple, la clé de ces tableaux sont des entiers :

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

Mais la clé de ces tableaux sont des chaînes :

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.

De plus, selon le doc ,

La taille d'un entier dépend de la plate-forme, bien qu'une valeur maximale d'environ deux milliards soit la valeur habituelle (c'est-à-dire 32 bits signés). Les plates-formes 64 bits ont généralement une valeur maximale d'environ 9E18, à l'exception de Windows, qui est toujours de 32 bits. PHP ne prend pas en charge les entiers non signés.

La clé de ce tableau peut donc être ou non un entier - cela dépend de votre plate-forme.

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

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"))donne

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

mais sur cette démo en direct sur codepad (PHP 5.2.5), la même expression donne

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

La clé est donc un entier dans un environnement mais une chaîne dans un autre, même s'il 2147483647s'agit d'un entier 32 bits signé valide .

Pang
la source
2
Sauf, comme je le mentionne ci-dessous, cela implique de créer un tableau en double de celui qui est vérifié, ce qui le rend très coûteux pour les grands tableaux et une source potentielle de pannes de mémoire insuffisante sur les hôtes partagés.
podperson
35

En termes de vitesse:

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

Côté mémoire:

function isAssoc($array)
{
    $array = array_keys($array); return ($array !== array_keys($array));
}
Alix Axel
la source
le tableau suivant: tableau (02 => 11,1,2,456); est indiqué comme n'ayant pas de clés numériques en utilisant l'algorithme ci-dessus, même si 02 === 2
Galileo_Galilei
20
function checkAssoc($array){
    return  ctype_digit( implode('', array_keys($array) ) );
}
dsims
la source
2
C'est la seule réponse (au moment de mon commentaire) qui peut traiter les éléments suivants: $ array = array (0 => 'blah', 2 => 'yep', 3 => 'wahey')
Shabbyrobe
mais 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)
Captain kurO
1
@CaptainkurO Vous voulez dire numérique. Il s'agit d'un tableau associatif.
devios1
1
Cette fonction renvoie truesi 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. Donc array(0=>'blah', 2=>'yep', 3=>'wahey'), array(0=>'blah', 2=>'yep', 1=>'wahey')et array('blah', 'yep', 'wahey')sont tous associatifs selon cette fonction, alors que ce array('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')n'est pas le cas.
Pang
@CaptainkurO vous avez tort. «1» et «2» seront stockés sous forme d'entiers. Lisez la partie citée de la réponse de l'écureuil du 11 mai 2011 à 19h34. PHP ne stocke pas de clés de chaîne qui ressemblent exactement à des entiers. Il les convertit en entiers.
Buttle Butkus
20

En fait, le moyen le plus efficace est donc:

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

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

anon
la source
1
Intelligent, mais pas bon. Pourquoi est-ce "le plus efficace"? Il serait beaucoup plus lisible de simplement comparer les array_keys ($ a) à range (0, count ($ a)). La solution la plus intelligente est rarement la meilleure de mon expérience. Surtout quand être intelligent n'ajoute littéralement aucune valeur à l'alternative évidente et propre.
Shane H
4
Cette fonction renvoie truepour array(1=>"a")mais falsepour array("a"=>"a"). Serait plus significatif s'il !=est remplacé par !==.
Pang
1
@Pang vous avez raison. Je pensais que votre commentaire devait sûrement être faux au début, mais, à ma grande surprise, [0] == ['a']en PHP (depuis 0 == 'a', et, en effet 0 == 'banana'). L' ==opérateur de PHP est fou.
Mark Amery
2
Ce n'est pas efficace dans la mesure où cela implique d'appeler array_keys par rapport à une simple vérification jusqu'à ce que vous trouviez un index entier non séquentiel. Sous le capot, vous le faites de toute façon , mais vous avez déjà dupliqué un grand tableau.
podperson
17

J'ai utilisé les deux array_keys($obj) !== range(0, count($obj) - 1)et array_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_keyset array_valuessont 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:

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

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 deux ifblocs.

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.

podperson
la source
13

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:

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

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:

  • Côté mémoire: pas de copie des données ou des plages de clés. Faire un array_values ​​ou array_keys peut sembler plus court (moins de code) mais gardez à l'esprit ce qui se passe en arrière-plan une fois que vous avez fait cet appel. Oui, il y a plus de déclarations (visibles) que dans certaines autres solutions, mais ce n'est pas ce qui compte, n'est-ce pas?
  • Temps sage: Outre le fait que la copie / extraction de données et / ou de clés prend également du temps, cette solution est plus efficace que de faire une foreach. Encore une fois, un foreach peut sembler plus efficace pour certains car il est plus court en notation, mais en arrière-plan, foreach appelle également reset, key et ensuite pour faire une boucle. Mais en plus, il appelle également valid pour vérifier la condition de fin, ce qui est évité ici en raison de la combinaison avec la vérification entière.

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.

Niels Ockeloen
la source
1
C'est la meilleure réponse. La définition du tableau "associatif" ou "numérique" dépend de la situation spécifique.
Pato
Si foreach est moins efficace que la méthode utilisée ici, à part l'inconvénient d'utiliser deux fonctions différentes, les performances de cette solution sont meilleures que la mienne (la précédente). Je soupçonne que ce n'est pas le cas, car foreach est recommandé comme le moyen le plus rapide de parcourir un tableau.
podperson
7

Cette fonction peut gérer:

  • tableau avec trous dans l'index (par exemple 1,2,4,5,8,10)
  • tableau avec clés "0x": par exemple, la clé '08' est associative tandis que la clé '8' est séquentielle.

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.

function is_asso($a){
    foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
    return FALSE;
}
LazNiko
la source
1
"si l'une des clés n'est PAS un entier, c'est un tableau associatif, sinon c'est séquentiel" - hein? Non, c'est tout simplement faux. Il est possible de discuter de ce qui constitue un tableau "associatif", mais la signification de "séquentiel" est assez claire, et ce n'est pas la même chose que toutes les clés étant des nombres.
Mark Amery
Si l'une des clés n'est PAS un entier, elle EST associative par nature, cependant, elle n'est séquentielle que si les clés vont de 0 - longueur (tableau) - 1. Elle est NUMÉRIQUE cependant, si toutes les clés sont seulement numérotées, mais peuvent ou peut ne pas fonctionner avec de nombreuses fonctions de tableau qui nécessitent un tableau séquentiel. Si vous convertissez le tableau numérique avec des trous en séquentiel en exécutant array_values ​​(array) dessus, il sera converti en séquentiel.
geilt
7

J'ai remarqué deux approches populaires pour cette question: l'une utilisant array_values()et l'autre utilisant key(). Pour savoir ce qui est plus rapide, j'ai écrit un petit programme:

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

La sortie du programme sur PHP 5.2 sur CentOS est la suivante:

Temps pris avec la méthode # 1 = 10,745 ms
Temps pris avec la méthode # 2 = 18,239 ms

La sortie sur PHP 5.3 a donné des résultats similaires. De toute évidence, l'utilisation array_values()est beaucoup plus rapide.

Manu Manjunath
la source
mauvaise référence. Vous n'avez pas testé de grands tableaux. Sur mon ordinateur à partir de 10K + éléments, la méthode # 2 est plus rapide. Essayez avec$arrays = Array( 'Array #1' => range(0, 50000), );
nonsensei
7

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

// Too short :)
function is_assoc($arr) {
    ksort($arr);
    return json_encode($arr)[0] === '{';
}
MAChitgarha
la source
Le ksort () n'est pas nécessaire à mon avis. Cette solution fonctionne mais elle doit tester si $ arr est nul et si json_encode échoue, donc un try / catch. + ce n'est pas vraiment optimal si $ arr est gros.
lucbonnin
7

Il existe déjà de nombreuses réponses, mais voici la méthode sur laquelle Laravel s'appuie dans sa classe 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;
}

Source: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php

Ben
la source
1
@Casey array_keys($keys)renverra un tableau séquentiel de nombres (0 ... X) qui a la même longueur que le tableau d'origine. Par exemple array_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)
valepu
Cet algorithme est fou, facile, compréhensible.
Benyi
Cela ne fonctionnera pas si vous disposez d'un tableau séquentiel de lignes associatives.
lucbonnin
5
function array_is_assoc(array $a) {
    $i = 0;
    foreach ($a as $k => $v) {
        if ($k !== $i++) {
            return true;
        }
    }
    return false;
}

Rapide, concis et efficace en mémoire. Aucune comparaison coûteuse, appel de fonction ou copie de tableau.

Jesse
la source
4

En utilisant l' extension PHP xarray

Vous pouvez le faire très rapidement (environ 30 fois plus vite en PHP 5.6):

if (array_is_indexed($array)) {  }

Ou:

if (array_is_assoc($array)) {  }
c9s
la source
3

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:

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

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.

pieds nuageux
la source
encore un point. tableau sous forme [1,2,null,4]échouera, mais c'est un tableau correct. j'ai donc ajouté des améliorations sur stackoverflow.com/a/25206156/501831 avec array_key_existsvérification de l' addition )
lazycommit
-1; isset()est le mauvais outil ici car il retournera false si la valeur est définie mais l'est null, comme l'a souligné @lazycommit.
Mark Amery
3

Ma solution:

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

array_mergesur un seul tableau réindexera toutes les integerclés, mais pas les autres. Par exemple:

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

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

Donc, si une liste (un tableau non associatif) est créée, ['a', 'b', 'c']une valeur est supprimée unset($a[1])puis array_mergeappelée, la liste est réindexée à partir de 0.

ByScripts
la source
-1; c'est 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.
Mark Amery
3

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.

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

Depuis 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";
}
TylerY86
la source
2

Voici la méthode que j'utilise:

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

Notez que cela ne tient pas compte des cas spéciaux comme:

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

unset($a[1]);

assert( true === is_associative($a) );

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

AL le X
la source
2
<?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);
}

?>

Ces deux exemples, qui ont marqué le plus de points, ne fonctionnent pas correctement avec des tableaux comme $array = array('foo' => 'bar', 1)

KillEveryBody
la source
+1 Votre is_list () est IMO la meilleure réponse. Certaines personnes n'ont aucune idée de la complexité du temps et de l'espace, et de la fonction scriptée native vs PHP ...
e2-e4
2

Cela fonctionnerait aussi ( démo ):

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

Veuillez noter que le point principal de cette réponse est de vous informer de l'existence de SplFixedArrayet non de vous encourager à utiliser des exceptions pour ce type de tests.

Gordon
la source
2

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.

<?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;
}
David Farrell
la source
2

Un de plus rapide depuis la source . Ajuster l'encodage de json_encode(et bson_encode). Il en va de même pour la conformité aux tableaux 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__)
        );
    }
}
lazycommit
la source
1
Pourquoi issetet array_key_exists? cette dernière ne suffirait-elle pas?
mcfedr
@mcfedr oui, ce serait le cas - la isset()vérification ici est complètement redondante.
Mark Amery
@mcfedr, @ mark-amery pour des raisons de performances. isset()est plus rapide que array_key_exists(). voir ilia.ws/archives/…
lazycommit
@lazycommit Cela va dépendre de votre tableau, puis de son meilleur avec ou sans, pas que ce soit susceptible d'avoir un tableau avec beaucoup de nulls, 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èques
mcfedr
2
si vous avez besoin de vérifier si cela conviendrait json_encode, vous pouvez simplement vérifier le premier symbole de la chaîne, renvoyé par json_encode($your_arr)- que ce soit [ou {;-)
pilat
2

Serait-ce la solution?

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

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é.

Kat Lim Ruiz
la source
Cette fonction renvoie false pour les deux array("a", "b")et array("a", "b" => "B")comme elle vérifie uniquement la première clé. BTW, is_longest juste un alias deis_int .
Pang
1
très franchement, je pense que ce serait très efficace dans la grande majorité des cas, et est beaucoup plus efficace que les alternatives. Si vous comprenez les conséquences de cette méthode et réalisez qu'elle fonctionnera pour vous, c'est probablement le meilleur choix.
Gershom
C'est tout simplement faux; il ne regarde que la première clé.
Mark Amery
@MarkAmery la question demandait comment différencier purement les tableaux séquentiels des tableaux purement associatifs. Cette réponse fait exactement cela et est la plus efficace de toutes. Avoir un comportement indéfini pour les tableaux mixtes est parfaitement bien dans le contexte de la question. +1
Tobia
@Tobia Je ne pense pas que la plupart des gens seraient d'accord avec vous pour classer, disons, [7 => 'foo', 2 => 'bar']un tableau "mixte" qui est partiellement mais pas "purement" séquentiel. Cela me semble une utilisation manifestement incorrecte des mots.
Mark Amery
2

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.

public function is_sequential( $arr = [] ){
    if( !is_array( $arr ) || empty( $arr ) ) return false;

    $i = 0;

    $total = count( $arr );

    foreach( $arr as $key => $value ) if( $key !== $i++ ) return false;

    return true;
}

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.

geilt
la source
1

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

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

résultats:

==== 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
sensi
la source
1

Ou vous pouvez simplement utiliser ceci:

Arr::isAssoc($array)

qui vérifiera si le tableau contient une clé non numérique ou:

Arr:isAssoc($array, true)

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.

Minwork
la source
0

À 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 à:

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

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

Daren Thomas
la source
1
Normalement, il suffit de supposer que le tableau est le type souhaité. Mais dans mon cas, je boucle sur un tableau multidimensionnel et je formate la sortie en fonction du type de tableau d'un nœud donné.
Wilco
0

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.

function isHash($array) {
    if (!is_array($array)) return false;
    $diff = array_diff_assoc($array, array_values($array));
    return (empty($diff)) ? false : true;
}
philroy
la source
-1; cela utilise de la O(n)mémoire supplémentaire lorsqu'il $arraya des néléments, et l'écriture (someboolean) ? false : trueau lieu de !somebooleanest horrible et verbeuse gratuitement.
Mark Amery