PHP trata todas las matrices como asociativas, por lo que no hay funciones integradas. ¿Alguien puede recomendar una forma bastante eficiente de verificar si una matriz contiene solo teclas numéricas?
Básicamente, quiero poder diferenciar entre esto:
$sequentialArray = array('apple', 'orange', 'tomato', 'carrot');
y esto:
$assocArray = array('fruit1' => 'apple',
'fruit2' => 'orange',
'veg1' => 'tomato',
'veg2' => 'carrot');
if (isset($array[0]))
, lo cual es simple y rápido. Por supuesto, primero debe asegurarse de que la matriz no esté vacía, y debe tener algún conocimiento sobre los posibles contenidos de la matriz para que el método no pueda fallar (como numérico mixto / asociativo o no secuencial).Respuestas:
Has hecho dos preguntas que no son del todo equivalentes:
Considere cuál de estos comportamientos realmente necesita. (Puede ser que lo haga para sus propósitos).
La primera pregunta (simplemente comprobando que todas las teclas son numéricas) es respondida bien por el Capitán KurO .
Para la segunda pregunta (verificar si la matriz está indexada a cero y secuencial), puede usar la siguiente función:
fuente
isSequential()
tendría más sentido queisAssoc()
. En tal función, la matriz vacía debe verse como secuencial. La fórmula podría serarray() === $arr || !isAssoc($arr)
.array_key_exists
lugar deisset
porque si el elemento cero es un valor nulo, el valor isset devolverá falso incorrectamente. Un valor nulo normalmente debería ser un valor legítimo en dicha matriz.Para verificar simplemente si la matriz tiene claves no enteras (no si la matriz está indexada secuencialmente o indexada a cero):
Si hay al menos una clave de cadena,
$array
se considerará como una matriz asociativa.fuente
$isIndexed = array_values($arr) === $arr;
. A lo que pregunto: ¿cómo crees quearray_values()
funciona? ¿Cómo crees que funciona===
aplicado a las matrices? La respuesta es, por supuesto, que también iteran sobre la matriz.var_dump([1.2 => 'foo', 1.5 => 'bar']);
, descubrirás que obtienes la matriz[1 => 'bar']
. No hay forma de averiguar el tipo original de una clave. Sí, todo esto es horrible; Las matrices de PHP son, con mucho, la peor parte del lenguaje, y la mayor parte del daño es irreparable y se debe a la idea de usar una sola construcción para las matrices tradicionales y los hashmaps tradicionales desde el principio.function isAssociative($arr) { foreach ($arr as $key => $value) { if (is_string($key)) return true; } return false; }
array(1 => 'a', 0 => 'b', 2 => 'c')
se convertirá enfalse
(matriz secuencial) mientras que debería sertrue
(matriz asociativa). toolsqa.com/data-structures/array-in-programming No estoy seguro de si la clave debe estar en orden ascendente. (0, 1, ...)Seguramente esta es una mejor alternativa.
fuente
===
perderá tiempo comprobando si los valores son iguales, aunque solo nos interesen las claves. Por esta razón, prefiero la$k = array_keys( $arr ); return $k === array_keys( $k );
versión.Muchos comentaristas en esta pregunta no entienden cómo funcionan las matrices en PHP. De la documentación de la matriz :
En otras palabras, no existe una clave de matriz de "8" porque siempre se convertirá (silenciosamente) al entero 8. Por lo tanto, no es necesario diferenciar entre enteros y cadenas numéricas.
Si desea la forma más eficiente de verificar una matriz para claves no enteras sin hacer una copia de parte de la matriz (como lo hace array_keys ()) o todo (como lo hace foreach):
Esto funciona porque la tecla () devuelve NULL cuando la posición actual de la matriz no es válida y NULL nunca puede ser una clave válida (si intenta usar NULL como una clave de matriz, se convierte silenciosamente a "").
fuente
0
hastacount($array)-1
, en este estricto orden. Una verificación preliminar conis_array()
puede ayudar. Agregue una variable creciente para verificar la secuencia de teclas:for ($k = 0, reset($array) ; $k === key($array) ; next($array)) ++$k;
eso resuelve el trato.foreach
lugar de la iteración explícita es aproximadamente dos veces más rápido.function isAssocStr($array) { for (reset($array); is_int(key($array)); next($array)) { if (is_null(key($array))) return false; } return true; }
Como lo indica el OP :
no es del todo razonable (en mi humilde opinión) escribir una función que verifique si una matriz es asociativa . Entonces, primero lo primero: ¿qué es una clave en una matriz PHP ?
Eso significa que hay 3 casos posibles:
Podemos verificar cada caso con las siguientes funciones.
Caso 1: todas las claves son numéricas / enteras .
Nota : Esta función también devuelve verdadero para matrices vacías.
Caso 2: todas las teclas son cadenas .
Nota : Esta función también devuelve verdadero para matrices vacías.
Caso 3. algunas teclas son cadenas , algunas teclas son numéricas / enteras .
Nota : Esta función también devuelve verdadero para matrices vacías.
Resulta que:
(que es por definición, como en " el conjunto vacío es un subconjunto de cualquier conjunto A porque todos sus elementos pertenecen a A ").
Ahora, para que una matriz sea una matriz "genuina" a la que todos estamos acostumbrados, lo que significa:
Podemos verificar con la siguiente función.
Caso 3a. Las teclas son numéricas / enteras , secuenciales y de base cero .
Nota : Esta función también devuelve verdadero para matrices vacías.
Advertencias / trampas (o, hechos aún más peculiares sobre las claves de matriz en PHP)
Teclas enteras
Las claves para estas matrices son enteros :
Teclas de cadena
Las claves para estas matrices son cadenas :
Teclas enteras que parecen cuerdas
Si cree que la clave
array("13" => "b")
es una cadena , está equivocado . Del documento aquí :Por ejemplo, la clave para estas matrices son enteros :
Pero la clave para estas matrices son las cadenas :
Además, según el documento ,
Por lo tanto, la clave para esta matriz puede o no ser un número entero ; depende de su plataforma.
Peor aún, PHP tiende a ser errores si el número entero está cerca del límite 2 31 = 2,147,483,648 (ver error 51430 , error 52899 ). Por ejemplo, en mi entorno local (PHP 5.3.8 en XAMPP 1.7.7 en Windows 7),
var_dump(array("2147483647" => "b"))
dapero en esta demostración en vivo en el teclado (PHP 5.2.5), la misma expresión da
Entonces la clave es un número entero en un entorno pero una cadena en otro, aunque
2147483647
es un número entero de 32 bits con signo válido .fuente
En cuanto a la velocidad:
En cuanto a la memoria:
fuente
fuente
array('1'=>'asdf', '2'=>'too')
será considerado como matriz asociativa, mientras que en realidad no es (son en realidad las teclas de cuerdas)true
si las claves son: cero, enteros (solo positivos), una cadena vacía o cualquier combinación de las anteriores, como la cadena "09". Esta función no tiene en cuenta el orden de las teclas. Entoncesarray(0=>'blah', 2=>'yep', 3=>'wahey')
,array(0=>'blah', 2=>'yep', 1=>'wahey')
yarray('blah', 'yep', 'wahey')
todos son asociativos de acuerdo con esta función, mientrasarray('a'=>'blah', 'b'=>'yep', 'c'=>'wahey')
que no lo es.En realidad, la forma más eficiente es así:
Esto funciona porque compara las claves (que para una matriz secuencial son siempre 0,1,2, etc.) con las claves de las claves (que siempre serán 0,1,2, etc.).
fuente
true
paraarray(1=>"a")
perofalse
paraarray("a"=>"a")
. Sería más significativo si!=
se reemplaza por!==
.[0] == ['a']
en PHP (desde entonces0 == 'a'
y, de hecho0 == 'banana'
). El==
operador de PHP está loco.He usado ambos
array_keys($obj) !== range(0, count($obj) - 1)
yarray_values($arr) !== $arr
(que son duales entre sí, aunque el segundo es más barato que el primero) pero ambos fallan para matrices muy grandes.Esto es porque
array_keys
yarray_values
son ambas operaciones muy costosas (ya que construir toda una nueva gama de tamaño más o menos a la del original).La siguiente función es más robusta que los métodos proporcionados anteriormente:
También tenga en cuenta que si no le importa diferenciar las matrices dispersas de las matrices asociativas, simplemente puede regresar
'assoc'
de ambosif
bloques.Finalmente, si bien esto puede parecer mucho menos "elegante" que muchas "soluciones" en esta página, en la práctica es mucho más eficiente. Casi cualquier matriz asociativa se detectará al instante. Solo las matrices indexadas se verificarán exhaustivamente, y los métodos descritos anteriormente no solo verifican las matrices indexadas exhaustivamente, sino que las duplican.
fuente
Creo que las siguientes dos funciones son la mejor manera de verificar "si una matriz es asociativa o numérica". Dado que 'numérico' podría significar solo teclas numéricas o solo teclas numéricas secuenciales, a continuación se enumeran dos funciones que verifican cualquiera de las condiciones:
La primera función verifica si cada clave es un valor entero. La segunda función verifica si cada clave es un valor entero y además verifica si todas las claves son secuenciales comenzando en $ base, que por defecto es 0 y, por lo tanto, puede omitirse si no necesita especificar otro valor base. La tecla ($ my_array) devuelve nulo si el puntero de lectura se mueve más allá del final de la matriz, que es lo que termina el ciclo for y hace que la declaración después del ciclo for sea verdadera si todas las claves son enteras. Si no, el ciclo finaliza prematuramente porque una clave es de tipo cadena, y la declaración después del ciclo for devolverá falso. La última función además agrega uno a $ base después de cada comparación, para poder verificar si la siguiente clave es del valor correcto. La comparación estricta hace que también verifique si la clave es de tipo entero. La parte $ base = (int) $ base en la primera sección del bucle for se puede omitir cuando se omite $ base o si se asegura de que solo se llame usando un número entero. Pero como no puedo estar seguro para todos, lo dejé. La declaración se ejecuta solo una vez, de todos modos. Creo que estas son las soluciones más eficientes:
Recuerde que una clave de matriz solo puede ser un entero o una cadena, y una cadena estrictamente numérica como "1" (pero no "01") se traducirá en un entero. Lo que hace que la comprobación de una clave entera sea la única operación necesaria además de contar si desea que la matriz sea secuencial. Naturalmente, si is_indexed_array devuelve falso, la matriz puede verse como asociativa. Digo "visto", porque de hecho todos lo son.
fuente
Esta función puede manejar:
La idea es simple: si una de las claves NO es un número entero, es una matriz asociativa, de lo contrario es secuencial.
fuente
Noté dos enfoques populares para esta pregunta: uno usando
array_values()
y otro usandokey()
. Para averiguar cuál es más rápido, escribí un pequeño programa:La salida para el programa en PHP 5.2 en CentOS es la siguiente:
La salida en PHP 5.3 arrojó resultados similares. Obviamente usar
array_values()
es mucho más rápido.fuente
$arrays = Array( 'Array #1' => range(0, 50000), );
Una forma de abordar esto es a cuestas
json_encode
, que ya tiene su propio método interno de diferenciar entre una matriz asociativa y una matriz indexada para generar el JSON correcto.Puede hacerlo comprobando si el primer carácter devuelto después de la codificación es una
{
(matriz asociativa) o una[
(matriz indexada).fuente
Ya hay muchas respuestas, pero aquí está el método en el que se basa Laravel dentro de su clase Arr:
Fuente: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
fuente
array_keys($keys)
devolverá una matriz secuencial de números (0 ... X) que tiene la misma longitud que la matriz original. Por ejemploarray_keys(["a", "b", "c"]) = [0, 1, 2];
array_keys([0, 1, 2]) = [0, 1, 2]
(es una matriz secuencial porque[0, 1, 2] !== [0, 1, 2]
). Otro ejemplo:array_keys(["a" => 5, "b" => 7, "c" => 10]) = ["a", "b", "c"];
array_keys(["a", "b", "c"]) = [0, 1, 2]
(es una matriz asociativa porque["a", "b", "c"] !== [0, 1, 2]
). Espero que sea claro (difícil de explicar ampliamente en un comentario, al menos para mí)Rápido, conciso y eficiente en memoria. Sin comparaciones costosas, llamadas a funciones o copia de matrices.
fuente
Mediante el uso de la extensión PHP xarray
Puede hacer esto muy rápido (aproximadamente 30 veces más rápido en PHP 5.6):
O:
fuente
Sé que es un poco inútil agregar una respuesta a esta gran cola, pero aquí hay una solución legible de O (n) que no requiere duplicar ningún valor:
En lugar de verificar las teclas para ver si son todas numéricas, itera sobre las teclas que estarían allí para una matriz numérica y asegúrese de que existan.
fuente
[1,2,null,4]
fallará, pero es la matriz correcta. así que he agregado algunas mejoras en stackoverflow.com/a/25206156/501831 conarray_key_exists
verificación de adición )isset()
es la herramienta incorrecta aquí porque devolverá falso si se establece el valor pero esnull
, como lo señala @lazycommit.Mi solución:
array_merge
en una sola matriz reindexará todas lasinteger
claves, pero no otras. Por ejemplo:Entonces, si se crea una lista (una matriz no asociativa)
['a', 'b', 'c']
, se elimina un valor yunset($a[1])
luegoarray_merge
se llama, la lista se reindexa a partir de 0.fuente
O(n)
usa en memoria adicional (ya que creó múltiples matrices nuevas con tantos elementos como sea posible$array
), la respuesta no aborda la ambigüedad de la pregunta que se hace ni explica exactamente cómo está definiendo una lista / matriz no asociativa, e incluso Si ninguno de estos puntos fuera cierto, no está claro que esto agregue algún valor en comparación con otras respuestas ya publicadas.Después de algunas evaluaciones comparativas locales, depuración, pruebas de compilación, creación de perfiles y abuso de 3v4l.org para comparar en más versiones (sí, recibí una advertencia para detener) y comparar con cada variación que pude encontrar ...
Le doy una función de prueba de matriz asociativa de mejor escenario promedio peor caso derivada orgánicamente que en el peor de los casos es aproximadamente tan buena o mejor que todos los demás escenarios de caso promedio.
Desde https://3v4l.org/rkieX :
fuente
Aquí está el método que uso:
Tenga en cuenta que esto no tiene en cuenta casos especiales como:
Lo siento, no puedo ayudarte con eso. También es algo eficaz para matrices de tamaño decente, ya que no hace copias innecesarias. Son estas pequeñas cosas las que hacen que Python y Ruby sean mucho más agradables para escribir ...: P
fuente
Ambos ejemplos, que obtuvieron la mayor cantidad de puntos, no funcionan correctamente con matrices como
$array = array('foo' => 'bar', 1)
fuente
Esto también funcionaría ( demo ):
Tenga en cuenta que el punto principal de esta respuesta es informarle sobre la existencia
SplFixedArray
y no alentarlo a usar Excepciones para este tipo de pruebas.fuente
Creo que la definición de una matriz escalar variará según la aplicación. Es decir, algunas aplicaciones requerirán un sentido más estricto de lo que califica como una matriz escalar, y algunas aplicaciones requerirán un sentido más laxo.
A continuación presento 3 métodos de rigurosidad variable.
fuente
Uno más rápido desde la fuente . Ajuste la codificación de
json_encode
(ybson_encode
). También tiene conformidad con la matriz de JavaScript.fuente
isset
yarray_key_exists
? ¿No sería esto último suficiente?isset()
comprobación aquí es completamente redundante.isset()
es más rápido quearray_key_exists()
. ver ilia.ws/archives/…null
s, pero tampoco es probable que tenga una matriz lo suficientemente grande como para que haya una notable diferencia de rendimiento mediante el uso de ambos controlesjson_encode
, simplemente puede verificar el primer símbolo de la cadena, devuelto porjson_encode($your_arr)
- si es[
o{
;-)¿Podría ser esta la solución?
La advertencia es obviamente que el cursor de la matriz se restablece, pero yo diría que probablemente la función se usa antes de que la matriz se recorra o se use.
fuente
array("a", "b")
yarray("a", "b" => "B")
ya que solo verifica la primera clave. Por cierto,is_long
es solo un alias deis_int
.[7 => 'foo', 2 => 'bar']
como una matriz "mixta" que es parcial pero no "puramente" secuencial. Eso me parece un uso claramente incorrecto de las palabras.Muchas de las soluciones aquí son elegantes y bonitas, pero no escalan bien y requieren mucha memoria o CPU. La mayoría está creando 2 nuevos puntos de datos en la memoria con esta solución desde ambos lados de la comparación. Cuanto mayor sea la matriz, más difícil y más largo será el proceso y la memoria utilizados, y perderá el beneficio de la evaluación de cortocircuito. Hice algunas pruebas con algunas ideas diferentes. Tratando de evitar array_key_exists ya que es costoso, y también evitando crear nuevos conjuntos de datos grandes para comparar. Siento que esta es una manera simple de saber si una matriz es secuencial.
Ejecuta un solo recuento en la matriz principal y almacena un solo entero. Luego recorre la matriz y comprueba una coincidencia exacta mientras itera el contador. Deberías tener de 1 para contar. Si falla, se producirá un cortocircuito que le dará un aumento de rendimiento cuando sea falso.
Originalmente hice esto con un bucle for y buscando isset ($ arr [$ i]), pero esto no detectará claves nulas que requieren array_key_exists, y como sabemos, esa es la peor función para usar para la velocidad.
Actualizando constantemente las variables a través de foreach para verificar junto con el iterador que nunca crece más allá de su tamaño entero, usemos PHP, está integrado en la optimización de memoria, almacenamiento en caché y recolección de basura para mantenerlo con un uso de recursos muy bajo.
Además, argumentaré que usar array_keys en un foreach es una tontería cuando simplemente puede ejecutar $ key => $ value y verificar la clave. ¿Por qué crear el nuevo punto de datos? Una vez que abstrae las claves de la matriz, ha consumido más memoria de inmediato.
fuente
Ya se dan respuestas, pero hay demasiada desinformación sobre el rendimiento. Escribí este pequeño script de referencia que muestra que el método foreach es el más rápido.
Descargo de responsabilidad: los siguientes métodos se copiaron de las otras respuestas
resultados:
fuente
O simplemente puedes usar esto:
que verificará si la matriz contiene alguna clave no numérica o:
para verificar si la matriz es estrictamente secuencial (contiene claves int generadas automáticamente 0 a n-1 )
usando esta biblioteca
fuente
A menos que PHP tenga un valor incorporado para eso, no podrá hacerlo en menos de O (n), enumerando todas las claves y verificando el tipo de entero. De hecho, también debe asegurarse de que no haya agujeros, por lo que su algoritmo podría verse así:
¿Pero por qué molestarse? Simplemente suponga que la matriz es del tipo que espera. Si no lo es, simplemente explotará en tu cara, ¡esa es una programación dinámica para ti! Prueba tu código y todo estará bien ...
fuente
Comparo la diferencia entre las claves de la matriz y las claves del resultado de array_values () de la matriz, que siempre será una matriz con índices enteros. Si las claves son las mismas, no es una matriz asociativa.
fuente
O(n)
memoria adicional cuando$array
tienen
elementos, y escribir en(someboolean) ? false : true
lugar de!someboolean
es horrible y gratuito detallado.