2011-05-13 20 views
9

Me gustaría poder pasar una matriz a una función y hacer que la función se comporte de manera diferente dependiendo de si es una matriz de estilo "lista" o un estilo "hash" formación. Ej .: salidaDeterminar si una matriz es asociativa (hash) o no

myfunc(array("One", "Two", "Three")); // works 
myfunc(array(1=>"One", 2=>"Two", 3=>"Three")); also works, but understands it's a hash 

Poder algo como:

One, Two, Three 
1=One, 2=Two, 3=Three 

es decir: la función hace algo diferente cuando se "detecta" que está siendo pasado un hash en lugar de una matriz. ¿Puedes decir que procedo de un fondo Perl donde% hashes son referencias diferentes de @arrays?

Creo que mi ejemplo es significativo porque no podemos simplemente probar para ver si la clave es numérica, porque podría estar usando claves numéricas en su hash.

estoy buscando específicamente para evitar tener que utilizar el constructo más desordenado de myfunc(array(array(1=>"One"), array(2=>"Two"), array(3=>"Three")))

+2

Buscando algo como esto? http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential –

+0

Pregunta interesante. PHP desafortunadamente no distingue 'array ('a', 'b', 'c')' de 'array (0 => 'a', 1 => 'b', 2 => 'c')' ... – Tadeck

+1

PHP siempre almacenará las teclas numéricas 'array (" 1 "=>" 1 ")' como números enteros. No puedo detectar eso. Solo puede buscar claves de crecimiento continuo para diferenciar listas verdaderas de matrices indexadas. – mario

Respuesta

36

Sacado directamente del marco kohana.

public static function is_assoc(array $array) 
{ 
    // Keys of the array 
    $keys = array_keys($array); 

    // If the array keys of the keys match the keys, then the array must 
    // not be associative (e.g. the keys array looked like {0:0, 1:1...}). 
    return array_keys($keys) !== $keys; 
} 
+3

+1 por elegancia – pedromanoel

+0

Muy bonito por cierto. Todavía estoy tomando esto un poco en fe ... pero funciona en mi código, ¡así que gracias! –

+1

Esto falla para las matrices no asociativas que se han filtrado, como [5 => 'foo']. – ARW

7

trata de PHP todas las matrices como hashes, técnicamente, por lo que no es una forma exacta de hacer esto. Su mejor apuesta sería la siguiente creo:

if (array_keys($array) === range(0, count($array) - 1)) { 
    //it is a hash 
} 
+0

Esta es la única solución que se publicó, así que la aceptaré, a pesar de su limitación inherente de no tener en cuenta los índices de matriz no secuenciales. Esta pregunta: http://stackoverflow.com/questions/173400/php-arrays-a-good-way-to-check-if-an-array-is-associative-or-sequential tiene muchas más soluciones, ninguna de que son perfectos –

+0

"no secuencial" se puede resolver de manera muy sencilla mediante la clasificación. –

0

No, PHP no distingue matrices donde las claves son cadenas numéricas de las matrices donde las claves son números enteros en casos como los siguientes:

$a = array("0"=>'a', "1"=>'b', "2"=>'c'); 
$b = array(0=>'a', 1=>'b', 2=>'c'); 

var_dump(array_keys($a), array_keys($b)); 

genera:

array(3) { 
    [0]=> int(0) [1]=> int(1) [2]=> int(2) 
} 
array(3) { 
    [0]=> int(0) [1]=> int(1) [2]=> int(2) 
} 

(por encima de formato para facilitar la lectura)

0

Mi solución es conseguir claves de una matriz, como a continuación y comprobar que si la clave no es entero:

private function is_hash($array) { 
    foreach($array as $key => $value) { 
     return ! is_int($key); 
    } 
    return false; 
} 

Es un error para obtener array_keys de una matriz de hash, como a continuación: salida

array_keys(array(
     "abc" => "gfb", 
     "bdc" => "dbc" 
     ) 
); 

voluntad :

array(
     0 => "abc", 
     1 => "bdc" 
) 

lo tanto, no es una buena idea para compararlo con un rango de números como se menciona en los más valorados respuesta. Siempre dirá que es una matriz de dispersión si intenta comparar claves con un rango.

+0

Sígueme en tu función, porque me falta algo. Tienes un bucle foreach, pero vuelves en la primera iteración de ese ciclo. ¿Para qué sirve el bucle si solo devuelve si la primera clave es un número entero? ¿Quizás quiso establecer una bandera como verdadera y luego en nuestro ciclo si ES un número entero, establecer la bandera en falso? –

+0

; de lo contrario, siempre obtendrás un valor entero como clave de matriz, ¡por eso! –

+0

Esto está más cerca de la respuesta real en mi humilde opinión. Sin embargo, Tom Auger tiene un punto. Creo que sería más como: función privada is_hash ($ array) { foreach (array_keys ($ array) como $ clave) { if (is_int ($ key)) { return false; } } return true; } – Garvin

11

This benchmark da 3 métodos.

Aquí hay un resumen, ordenado de más rápido a más lento. Para obtener más información, lea el benchmark here completo.

1. Usando array_values ​​()

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

2.Usando array_keys()

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

3. Usando array_filter()

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

Sería bueno anotar esto con el punto de referencia real resultados en caso de que el enlace quede obsoleto Es muy importante tener en cuenta que el enfoque 'array_filter' es órdenes de magnitud __slower__ que los demás. –

Cuestiones relacionadas