manejo - imprimir datos de un array php
¿Cómo comprobar si la matriz de PHP es asociativa o secuencial? (30)
Aquí está el método que utilizo:
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'')) );
Tenga en cuenta que esto no tiene en cuenta los casos especiales como:
$a = array( 1, 2, 3, 4 );
unset($a[1]);
assert( true === is_associative($a) );
Lo siento, no puedo ayudarte con eso. También es algo de buen rendimiento 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 fáciles de escribir en ...: P
PHP trata todas las matrices como asociativas, por lo que no hay funciones integradas. ¿Alguien puede recomendar una manera 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'');
Creo que las siguientes dos funciones son la mejor manera de verificar "si una matriz es asociativa o numérica". Como ''numérico'' podría significar solo teclas numéricas o solo teclas numéricas secuenciales, a continuación se enumeran dos funciones que comprueban cualquiera de las dos condiciones:
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 primera función comprueba 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 a partir de $ base, que por defecto es 0 y, por lo tanto, puede omitirse si no necesita especificar otro valor base. key ($ my_array) devuelve null si el puntero de lectura se mueve más allá del final de la matriz, que es lo que finaliza el bucle for y hace que la declaración después del retorno del bucle for sea verdadera si todas las claves fueran enteras. Si no, el bucle finaliza prematuramente porque una clave es de tipo cadena, y la declaración después del bucle for devolverá false. 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 también hace que se 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 utilizando un número entero. Pero como no puedo estar seguro de todo el mundo, lo dejé. La declaración se ejecuta solo una vez, de todos modos. Creo que estas son las soluciones más eficientes:
- En cuanto a la memoria: no se pueden copiar datos o rangos de teclas. Hacer un array_values o array_keys puede parecer más corto (menos código), pero tenga en cuenta lo que sucede en segundo plano una vez que realiza esa llamada. Sí, hay más declaraciones (visibles) que en otras soluciones, pero eso no es lo que cuenta, ¿verdad?
- En cuanto al tiempo: además del hecho de que copiar / extraer datos y / o claves también lleva tiempo, esta solución es más eficiente que hacer un foreach. Nuevamente, un foreach puede parecer más eficiente para algunos porque es más corto en notación, pero en segundo plano, foreach también se llama reset, la tecla y al lado está el bucle. Pero además, también es válido para verificar la condición final, que se evita aquí debido a la combinación con la verificación de enteros.
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 convertirá en un entero. Esto es 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 en realidad todos lo son.
En realidad la forma más eficiente es así:
function is_assoc($array){
$keys = array_keys($array);
return $keys !== array_keys($keys);
}
Esto funciona porque compara las claves (que para una matriz secuencial siempre son 0,1,2, etc.) con las claves de las claves (que siempre serán 0,1,2, etc.).
Esta función puede manejar:
- matriz con agujeros en el índice (por ejemplo, 1,2,4,5,8,10)
- matriz con las teclas "0x": por ejemplo, la tecla ''08'' es asociativa, mientras que la tecla ''8'' es secuencial.
la idea es simple: si una de las claves NO es un número entero, es una matriz asociativa, de lo contrario es secuencial.
function is_asso($a){
foreach(array_keys($a) as $key) {if (!is_int($key)) return TRUE;}
return FALSE;
}
Has hecho dos preguntas que no son del todo equivalentes:
- En primer lugar, cómo determinar si una matriz solo tiene claves numéricas
- En segundo lugar, cómo determinar si una matriz tiene teclas numéricas secuenciales , comenzando desde 0
Considere cuál de estos comportamientos realmente necesita. (Puede ser que cualquiera lo haga para sus propósitos).
La primera pregunta (simplemente verificando que todas las teclas son numéricas) la responde bien el capitán kurO .
Para la segunda pregunta (verificando si la matriz es indexada a cero y secuencial), puede usar la siguiente función:
function isAssoc(array $arr)
{
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
var_dump(isAssoc(array(''a'', ''b'', ''c''))); // false
var_dump(isAssoc(array("0" => ''a'', "1" => ''b'', "2" => ''c''))); // false
var_dump(isAssoc(array("1" => ''a'', "0" => ''b'', "2" => ''c''))); // true
var_dump(isAssoc(array("a" => ''a'', "b" => ''b'', "c" => ''c''))); // true
He usado array_keys($obj) !== range(0, count($obj) - 1)
y array_values($arr) !== $arr
(que son duales entre sí, aunque el segundo es más barato que el primero) pero ambos fallan para arreglos muy grandes.
Esto se debe a que array_keys
y array_values
son operaciones muy costosas (ya que crean una nueva matriz de tamaño aproximadamente la del original).
La siguiente función es más robusta que los métodos proporcionados anteriormente:
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;
}
También tenga en cuenta que si no le importa diferenciar las matrices dispersas de las matrices asociativas, simplemente puede devolver ''assoc''
de ambas if
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 será detectada instantáneamente. Solo los arreglos indexados serán revisados exhaustivamente, y los métodos descritos anteriormente no solo verifican los arreglos indexados exhaustivamente, sino que los duplican.
Mediante el uso de la extensión PHP xarray
Puede hacerlo muy rápido (aproximadamente 30 veces más rápido en PHP 5.6):
if (array_is_indexed($array)) { }
O:
if (array_is_assoc($array)) { }
Mi solución:
function isAssociative(array $array)
{
return array_keys(array_merge($array)) !== range(0, count($array) - 1);
}
array_merge
en una sola matriz reindexará todas las claves de integer
, pero no otras. Por ejemplo:
array_merge([1 => ''One'', 3 => ''Three'', ''two'' => ''Two'', 6 => ''Six'']);
// This will returns [0 => ''One'', 1 => ''Three'', ''two'' => ''Two'', 2 => ''Six'']
Entonces, si se crea una lista (una matriz no asociativa) [''a'', ''b'', ''c'']
luego se elimina un valor sin establecer unset($a[1])
luego se llama a array_merge
, la lista se reindexa a partir de 0.
Muchos comentaristas en esta pregunta no entienden cómo funcionan las matrices en PHP. De la documentación de la matriz :
Una clave puede ser un entero o una cadena. Si una clave es la representación estándar de un número entero, se interpretará como tal (es decir, "8" se interpretará como 8, mientras que "08" se interpretará como "08"). Las flotaciones en la clave se truncan a entero. Los tipos de matrices indexadas y asociativas son del mismo tipo en PHP, que pueden contener índices enteros y de cadena.
En otras palabras, no existe tal cosa como una clave de matriz de "8" porque siempre se convertirá (silenciosamente) al número entero 8. Por lo tanto, no es necesario tratar de diferenciar entre enteros y cadenas numéricas.
Si desea la forma más eficiente de verificar una matriz en busca de claves no enteras sin hacer una copia de parte de la matriz (como hace array_keys ()) o toda la misma (como hace foreach):
for (reset($my_array); is_int(key($my_array)); next($my_array));
$onlyIntKeys = is_null(key($my_array));
Esto funciona porque key () 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 "").
Noté dos enfoques populares para esta pregunta: uno usando array_values()
y otro usando key()
. Para saber cuál es más rápido, escribí un pequeño programa:
$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 salida para el programa en PHP 5.2 en CentOS es la siguiente:
Tiempo tomado con el método # 1 = 10.745ms
Tiempo tomado con el método # 2 = 18.239ms
La salida en PHP 5.3 produjo resultados similares. Obviamente, usar array_values()
es mucho más rápido.
Para verificar simplemente si la matriz tiene claves no enteras (no si la matriz está indexada secuencialmente o indexada a cero):
function has_string_keys(array $array) {
return count(array_filter(array_keys($array), ''is_string'')) > 0;
}
Si hay al menos una clave de cadena, $array
se considerará como una matriz asociativa.
Según lo indicado por el OP :
PHP trata todas las matrices como asociativas
no es del todo sensato (IMHO) escribir una función que verifique si una matriz es asociativa . Entonces, primero lo primero: ¿qué es una clave en una matriz de PHP ?
La clave puede ser un entero o una cadena .
Eso significa que hay 3 casos posibles:
- Caso 1. Todas las teclas son numéricas / enteras .
- Caso 2. Todas las claves son cuerdas .
- Caso 3. algunas claves son cadenas , algunas claves son numéricas / enteros .
Podemos comprobar cada caso con las siguientes funciones.
Caso 1: todas las teclas son numéricas / enteras .
Nota : Esta función también devuelve true para arreglos vacíos.
//! 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);
}
Caso 2: todas las claves son cuerdas .
Nota : Esta función también devuelve true para arreglos vacíos.
//! 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);
}
Caso 3. algunas claves son cadenas , algunas claves son numéricas / enteros .
Nota : Esta función también devuelve true para arreglos vacíos.
//! 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;
}
Resulta que:
- Si el valor no es una matriz , las 3 funciones devuelven falso .
- Si el valor es una matriz vacía , las 3 funciones devuelven verdadero
(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 "). - Si el valor es una matriz no vacía , exactamente 1 función devuelve verdadero .
Ahora, para que una matriz sea una matriz "genuina" a la que todos estamos acostumbrados, lo que significa:
- Sus claves son todas numéricas / enteras .
- Sus claves son secuenciales (es decir, aumentan en el paso 1).
- Sus llaves empiezan desde cero .
Podemos comprobar con la siguiente función.
Caso 3a. Las claves son numéricas / enteras , secuenciales y basadas en cero .
Nota : Esta función también devuelve true para arreglos vacíos.
//! 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);
}
Advertencias / errores (o, incluso, datos más curiosos sobre las claves de matriz en PHP)
Teclas enteras
Las claves para estas matrices son integers :
array(0 => "b");
array(13 => "b");
array(-13 => "b"); // Negative integers are also integers.
array(0x1A => "b"); // Hexadecimal notation.
Teclas de cadena
Las claves para estas matrices son strings :
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://.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!
Teclas enteras que parecen cuerdas
Si crees que la clave en array("13" => "b")
es una cadena , estás equivocado . Desde el doc aquí :
Las cadenas que contienen enteros válidos se convertirán al tipo de entero. Por ejemplo, la clave "8" se almacenará realmente en 8. Por otra parte, "08" no se convertirá, ya que no es un entero decimal válido.
Por ejemplo, la clave para estas matrices son enteros :
array("13" => "b");
array("-13" => "b"); // Negative, ok.
Pero la clave para estas matrices son las cadenas :
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.
Además, según el doc .
El tamaño de un entero depende de la plataforma, aunque un valor máximo de aproximadamente dos mil millones es el valor habitual (es decir, 32 bits con signo). Las plataformas de 64 bits generalmente tienen un valor máximo de aproximadamente 9E18, excepto para Windows, que siempre es de 32 bits. PHP no soporta enteros sin signo.
Por lo tanto, la clave de esta matriz puede ser o no un entero , depende de su plataforma.
array("60000000000" => "b"); // Array key could be integer or string, it can fit into a 64-bit (but not 32-bit) integer.
Peor aún, PHP tiende a tener 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"))
da
array(1) {
[2147483647]=>
string(1) "b"
}
pero en esta demostración en vivo en el teclado (PHP 5.2.5), la misma expresión da
array(1) {
["2147483647"]=>
string(1) "b"
}
Por lo tanto, la clave es un entero en un entorno pero una cadena en otro, aunque 2147483647
es un entero de 32 bits con signo válido.
Seguramente esta es una mejor alternativa.
<?php
$arr = array(1,2,3,4);
$isIndexed = array_values($arr) === $arr;
Una forma de abordar esto es a cuestas en json_encode
, que ya tiene su propio método interno de diferenciación entre una matriz asociativa y una matriz indexada para generar el JSON correcto.
Puede hacerlo verificando si el primer carácter devuelto después de la codificación es un {
(matriz asociativa) o un [
(matriz indexada).
// Too short :)
function is_assoc($arr) {
ksort($arr);
return json_encode($arr)[0] === ''{'';
}
Ya hay muchas respuestas, pero aquí está el método en el que Laravel confía dentro de su clase 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;
}
Fuente: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Support/Arr.php
¿Podría ser esta la solución?
public static function isArrayAssociative(array $array) {
reset($array);
return !is_int(key($array));
}
La advertencia es, obviamente, que el cursor de la matriz se restablece, pero yo diría que probablemente la función se use antes de que la matriz se cruce o se use.
En cuanto a la velocidad:
function isAssoc($array)
{
return ($array !== array_values($array));
}
En cuanto a la memoria:
function isAssoc($array)
{
$array = array_keys($array); return ($array !== array_keys($array));
}
Después de algunas evaluaciones locales, depuración, sondeo de compiladores, creación de perfiles y uso indebido de 3v4l.org para realizar pruebas comparativas en más versiones (sí, recibí una advertencia para detener) y compararlas con cada variación que pudiera encontrar ...
Le entrego una función de prueba de matriz asociativa de mejor caso de peor promedio en el caso de origen orgánico que en el peor de los casos es aproximadamente tan buena o mejor que todos los otros escenarios de promedio de casos.
Que Dios tenga misericordia de nuestras almas.
/**
* 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;
}
Desde 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";
}
En mi opinión, una matriz debe aceptarse como asociativa si alguna de sus claves no es un número entero, por ejemplo, números flotantes y una cadena vacía ''''.
Además, los enteros no secuenciados deben considerarse asociativos como (0,2,4,6) porque este tipo de arreglos no se pueden usar con los bucles de esta manera:
$n =count($arr);
for($i=0,$i<$n;$i++)
La segunda parte de la función siguiente comprueba si las claves están indexadas o no. También funciona con claves con valores negativos. Por ejemplo (-1,0,1,2,3,4,5)
count() = 7 , max = 5, min=-1
if( 7 == (5-(-1)+1 ) // true
return false; // array not associative
/**
* isAssoc Checks if an array is associative
* @param $arr reference to the array to be checked
* @return bool
*/
function IsAssoc(&$arr){
$keys= array_keys($arr);
foreach($keys as $key){
if (!is_integer($key))
return true;
}
// if all keys are integer then check if they are indexed
if(count($arr) == (max($keys)-min($keys)+1))
return false;
else
return true;
}
Sé que es un poco inútil agregar una respuesta a esta enorme cola, pero aquí hay una solución legible O (n) que no requiere duplicar ningún valor:
function isNumericArray($array) {
$count = count($array);
for ($i = 0; $i < $count; $i++) {
if (!isset($array[$i])) {
return FALSE;
}
}
return TRUE;
}
En lugar de verificar las claves para ver si todas son numéricas, se debe iterar sobre las claves que estarían allí para una matriz numérica y asegurarse de que existan.
A menos que PHP tenga un componente 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 desea asegurarse de que no haya agujeros, por lo que su algoritmo podría tener el siguiente aspecto:
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 :)
Pero ¿por qué molestarse? Solo asume que la matriz es del tipo que esperas. Si no lo es, simplemente explotará en tu cara, ¡eso es programación dinámica para ti! Prueba tu código y todo estará bien ...
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 vago.
A continuación presento 3 métodos de rigor 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;
}
Esto también funcionaría ( demo ):
function array_has_numeric_keys_only(array $array)
{
try {
SplFixedArray::fromArray($array, true);
} catch (InvalidArgumentException $e) {
return false;
}
return true;
}
Tenga en cuenta que el punto principal de esta respuesta es informarle sobre la existencia SplFixedArray
y no animarlo a usar Excepciones para este tipo de pruebas.
Modificación en la respuesta más popular.
Esto requiere un poco más de procesamiento, pero es más preciso.
<?php
//$a is a subset of $b
function isSubset($a, $b)
{
foreach($a =>$v)
if(array_search($v, $b) === false)
return false;
return true;
//less effecient, clearer implementation. (uses === for comparison)
//return array_intersect($a, $b) === $a;
}
function isAssoc($arr)
{
return !isSubset(array_keys($arr), range(0, count($arr) - 1));
}
var_dump(isAssoc(array(''a'', ''b'', ''c''))); // false
var_dump(isAssoc(array(1 => ''a'', 0 => ''b'', 2 => ''c''))); // false
var_dump(isAssoc(array("0" => ''a'', "1" => ''b'', "2" => ''c''))); // false
//(use === in isSubset to get ''true'' for above statement)
var_dump(isAssoc(array("a" => ''a'', "b" => ''b'', "c" => ''c''))); // true
?>
Uno más rápido de la source . Encaja la codificación de json_encode
(y bson_encode
). Así ha javascript Arreglo de la matriz.
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__)
);
}
}
Ya se dieron respuestas, pero hay demasiada desinformación sobre el desempeño. 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 fueron copiados y pegados de las otras respuestas
<?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";
}
resultados:
==== 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
Yo 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.
function isHash($array) {
if (!is_array($array)) return false;
$diff = array_diff_assoc($array, array_values($array));
return (empty($diff)) ? false : true;
}
<?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);
}
?>
Ambos ejemplos, que obtuvieron la mayor cantidad de puntos, no funcionan correctamente con matrices como $array = array(''foo'' => ''bar'', 1)
function array_is_assoc(array $a) {
$i = 0;
foreach ($a as $k => $v) {
if ($k !== $i++) {
return true;
}
}
return false;
}
Rápido, conciso y eficiente en memoria. No hay comparaciones costosas, llamadas de función o copia de matriz.
function checkAssoc($array){
return ctype_digit( implode('''', array_keys($array) ) );
}