PHP-TUT-04 Matrices en PHP (I)

Facebooktwittergoogle_pluslinkedinmailFacebooktwittergoogle_pluslinkedinmail

PHP permite almacenar varias variables diferentes, que pueden almacenar valores distintos, bajo el mismo nombre, identificándolas mediante el uso de uno o más índices. Son las matrices. Podemos imaginar las matrices como las casillas de apartados postales en una oficina de correos. Todas pueden ser identificadas mediante, por ejemplo, el nombre de la oficina seguido del número de casilla, y cada una tendrá un contenido distinto.

El formato genérico es así:

nombreMatriz[índice 1][índice 2]…[índice N] = valor

Normalmente se emplean matrices con un solo índice o, como mucho, con dos, aunque se pueden emplear más, si usted lo necesita en algún caso (a mí, hasta la fecha, sólo se me ha presentado en una ocasión la necesidad de tres índices; normalmente, con un máximo de dos se cubre cualquier necesidad).

Las matrices se clasifican, según la naturaleza del índice empleado, en indexadas y asociativas. A continuación vamos a estudiar el uso y características de ambos tipos. En realidad se parecen bastante: el concepto fundamental es el mismo, como verá enseguida.

MATRICES INDEXADAS

Son aquéllas en las que el índice es un valor numérico. Para empezar, veamos cómo crearíamos una matriz con nombres de personas (aunque, por supuesto, podríamos usar otros valores):

$nombres = array ("Pedro", "Ana", "Carmen", "Alfredo", "Eva");

Con esto se habría creado una matriz de cinco elementos. Fíjese en que usamos la función array (). Esta función recibe, como argumentos, los elementos que queremos almacenar en la matriz, y la crea. A cada uno de ellos se le ha asignado un índice numérico secuencial, según el orden en que se hallan dispuestos en la declaración, empezando por 0. Para recuperar alguno de los elementos de la matriz usaremos la notación genérica siguiente:

$matriz [$n]

En esta notación, $n entre corchetes es un valor numérico referido al índice del elemento de la matriz que nos interesa. Como índice podemos usar un número o una expresión que lo represente.

Observe el script crearMatriz.php, que incorpora la línea en la que se crea la matriz y que luego muestra los valores almacenados en la página.

Con este código se verán los elementos de la matriz en la página. El primer elemento, que contiene Pedro es el que tiene el índice 0. El último elemento, que contiene Eva, es el que tiene asignado el índice 4. Si no especificamos lo contrario, los índices se empiezan a numerar, siempre, por 0. Si necesitamos que empiecen a numerarse por 1 (o por cualquier otro número, si a eso vamos) deberemos especificar el índice del primer elemento, así:

Incluso, podemos, si lo deseamos, usar índices no consecutivos, así:

Cuando se crea una matriz indexada de este modo PHP no reserva un espacio en memoria para los elementos no declarados, con lo que la matriz no ocupa más memoria que si hubiera creado los elementos de 0 a 4. Y, naturalmente, puedes crear nuevos elementos, incluso con índices intermedios, cuando lo necesites.

Algo que debes saber es que los elementos de una matriz no tienen que ser, necesariamente, del mismo tipo. En una matriz se pueden almacenar cadenas alfanuméricas, valores numéricos, valores booleanos, etc. Observa el script matrizVariosTipos.php, similar al anterior pero con contenidos de distintos tipos.

Al ejecutarlo verás que se muestran los valores almacenados en la matriz, como hacía el ejemplo anterior. Quizás lo que te llame la atención es el último valor. Es un true lógico y, como hemos visto en anteriores ejemplos, se muestra en la página como un 1 aunque, si deseas ver el contenido de un elemento de la matriz de forma más precisa, siempre puedes recurrir a var_dump(), así:

echo "<pre>";
var_dump($datosDiversos[3]);

Incluso puedes hacer un volcado de toda la matriz, así:

echo "<pre>";
var_dump($datosDiversos);

Las matrices no tienen un número inamovible de elementos. Si, una vez creada la matriz, necesitas añadir más elementos, puedes hacerlo simplemente declarando el elemento nuevo y su valor. Observa el script nuevoElemento.php:

Quiero llamar tu atención sobre la línea en la que se crea un nuevo elemento que no aparece en la declaración inicial de la matriz ($nombres[5] = "Susana";). Al ejecutar la página verás que funciona correctamente. Le he asignado al nuevo elemento el índice 5 porque sé que es el siguiente de la lista, ya que iban de 0 a 4. Esto no es necesario. Esta línea podría quedar, perfectamente, así:

$nombres[] = "Susana";

Al asignar un contenido a un elemento de la matriz sin especificar el índice de dicho elemento el intérprete de PHP crea, de modo automático, el siguiente índice al último empleado. Como, en nuestro ejemplo, el último índice creado es el 4, PHP creará el elemento 5 para almacenar el nuevo contenido.

A la hora de referirnos a uno de los elementos de una matriz podemos escribir el índice, o una variable que contenga el índice, tal como se muestra en el script situarIndice.php. Observa que he usado una variable donde he almacenado un valor numérico para referirme al índice de la matriz.

Esto nos será especialmente útil cuando aprendamos a manejar estructuras de control de flujo.

MATRICES ASOCIATIVAS

Usar índices numéricos en las matrices es muy práctico en ocasiones. A veces para referirse a un elemento de una matriz resulta interesante calcular su índice mediante operaciones aritméticas basadas en datos proporcionados por el usuario. Sin embargo, hay ocasiones en que el uso de índices numéricos es engorroso por la misma razón que lo es el nombrar a las variables de un script como $variable_1, $variable_2, etc. Simplemente, los índices numéricos no proporcionan ninguna referencia clara acerca del contenido de un elemento de la matriz. Además, existen algunas matrices específicas que, por su propia naturaleza, exigen otro manejo diferente. Para solucionar esta cuestión PHP implementa las matrices asociativas, en las que los índices son cadenas de texto que podemos definir como nos convenga. Vamos a crear una matriz con los datos personales de un amigo. Queremos almacenar en la matriz el nombre, la dirección y el teléfono de esta persona. Observa el script crearAsociativa.php:

Observe la línea resaltada, que corresponde a la declaración de la matriz. Hemos creado tres elementos que contienen los valores que deseábamos almacenar. Cada uno de estos elementos tiene un índice formado por una cadena alfanumérica. Los elementos, a su vez, pueden tener el tipo de valor que necesitemos, tal como ocurre con las matrices indexadas. Como es lógico, en una matriz asociativa también podemos poner, en lugar del índice, una variable que contenga dicho índice. Lo vemos en el script indiceDeAsociativa.php:

MATRICES MIXTAS

Visto lo anterior, parece que falta algo. Por ejemplo, supongamos que quieres almacenar en una matriz los datos personales de más amigos. La solución puede llegar de la mano de matrices con dos índices: uno numérico para referirse a cada amigo y otro asociativo para almacenar los datos de cada uno. Sería como un casillero en el que cada fila correspondería a un amigo y cada columna a un dato. Observa el script indexadaYAsociativa.php. Presta especial atención a la forma de declarar la matriz, ya que, en este caso, es un poco más compleja que en los anteriores.

En primer lugar, ejecuta la página en tu navegador para ver cómo funciona. Observa la declaración de la matriz. Es una sola línea lógica, aunque esté dispuesta en varias líneas físicas, para que el código quede más claro a la vista. Esto es muy habitual con declaraciones especialmente largas. PHP no reconoce el final de la línea lógica hasta que no encuentra el punto y coma (;), con lo que no nos dará ningún problema escribir código así. Lo que hacemos es declarar una matriz indexada en la que cada elemento es, a su vez, una matriz asociativa. Por esa razón dentro de cada elemento de la matriz indexada aparece de nuevo la función array ().

Ahora repara en la forma de acceder a un elemento de una matriz con dos índices. El modo genérico es el siguiente:

$matriz [$i1][$i2]

Por supuesto, en una matriz de dos índices puedes usar uno numérico y otro asociativo, los dos numéricos o los dos asociativos, según convenga en cada caso.

Una matriz con dos índices no tiene por qué tener el mismo número de elementos en cada fila. Supongamos que, en tu lista de amigos, te faltan algunos datos. Por ejemplo, puede ser que no conozcas la dirección o el teléfono de algunos de tus amigos. La declaración de la matriz podría quedar así:

 

Como ves, falta la dirección de Carlos Gómez y el teléfono de Carmen Pérez. Esta forma de declarar una matriz es perfectamente válida en PHP. Otros lenguajes también admiten la creación y uso de estas matrices irregulares. De hecho, muchas de las matrices de dos índices que use serán así.

EL TAMAÑO DE UNA MATRIZ

La función count () nos permite determinar el número de elementos de una matriz. Observa el script contarElementos.php:

La función count () recibe como argumento el nombre de la matriz de la cual queremos saber qué número de elementos tiene, y devuelve dicho número de elementos. En el código hay tres matrices que ya hemos usado antes. La función count () opera con matrices indexadas o asociativas indistintamente.

Observa que, en el caso de la primera matriz, la función count () nos informa de que hay cinco elementos, como debe ser. El hecho de que los índices no empiecen por cero o no sean consecutivos no influye para nada.

Un caso particular es la tercera matriz, que tiene dos índices. En este caso, la función count () sólo cuenta el índice principal (el de las filas, para entendernos). Si quieres determinar el número de elementos de una de las filas, puedes hacerlo como se muestra en el script otraCuenta.php. La función count (), en este caso, recibe como argumento una de las filas de la matriz.

ORDENAR UNA MATRIZ

La gestión de matrices aporta un elemento del que será necesario disponer en ocasiones: la capacidad de reordenación. Efectivamente, dada una matriz puedes escribir un script que necesite disponer de los datos en cierto orden. En una matriz indexada  la reordenación se basa en el valor de cada elemento. Una matriz asociativa puede ordenarse en función de la clave o del valor. Para llevar esto a efecto contamos con varias funciones. La función sort () recibe, como argumento, el nombre de una matriz indexada y la ordena según los contenidos de sus elementos, de menor a mayor. Si los contenidos son numéricos está claro cómo se hace la ordenación. Si son alfabéticos, se considera un elemento mayor que otro en base al código ASCII del primer carácter. Si éste es idéntico en ambos elementos, se compara el segundo carácter, y así sucesivamente. Si quieres consultar el código ASCII puedes hacerlo en este enlace. La sintaxis genérica de esta función es la siguiente:

sort ($matriz);

Al ejecutarla, la matriz no cambia de nombre. Simplemente se ordenan sus elementos como se ha indicado. Como alternativa, tenemos la función rsort (), cuya operativa es similar a la anterior, solo que efectuando el orden en sentido descendente, de mayor a menor.

ATENCIÓN. Estas funciones no deben ser empleadas sobre matrices asociativas, ya que reordenan los elementos por valor, pero no tienen en cuenta las claves, con lo cual se pierde la paridad clave-valor que hubiéramos establecido en cada elemento de la matriz. Para ordenar una matriz asociativa empleamos la función asort () para ordenar por el valor de cada elemento, de menor a mayor. También se puede usar arsort (), para ordenar por valor de mayor a menor. Si quieres usar la clave para la ordenación, emplea ksort (), para ordenar en sentido ascendente, o krsort (), para ordenar en sentido descendente. Estas cuatro últimas funciones sí mantienen cada clave asociada a su valor.

ORDENAR MATRICES MULTIDIMENSIONALES

Este es un tema peliagudo en muchos lenguajes de programación. Se trata de ordenar los elementos de una matriz bidimensional (que, cómo ya sabes, son, a su vez, matrices unidimensionales), por un criterio. Por ejemplo, en las matrices que hemos visto de amigos, podemos querer ordenarlas por el nombre. Afortunadamente, PHP cuenta con la función array_multisort(), concebida para hacer, precisamente, eso.

Esta es una necesidad tan habitual, y tan importante de resolver correctamente, que le hemos dedicado un artículo propio.

OTRAS FORMAS DE ORDENACIÓN

A la hora de ordenar una matriz contamos con algunas posibilidades más, propias de PHP, que, en ocasiones, nos resuelven necesidades concretas. Por ejemplo, una de las funciones más interesantes es natsort(), que realiza una ordenación de elementos por un orden “natural”. Para entender lo que esto significa, suponte que tenemos la siguiente matriz:

$numeros = array(1, 7, 18, 2, 3, 25, 6, 4, 44);

Si hacemos una ordenación normal, con la función sort() que ya conocemos, el resultado es el siguiente:

1, 18, 2, 25, 3, 4, 44, 6, 7

En cambio, si escribimos natsort($numeros); lo que obtenemos es:

1, 2, 3, 4, 6, 7, 18, 25, 44

Como ves, es una ordenación mucho más útil en la mayoría de los casos.

PHP cuenta con una función de ordenación (en realidad, tres) basada en funciones de usuario. Sin embargo, no vamos a hablar de esto ahora, hasta no estar familiarizados con este último concepto.

BÚSQUEDA DE ELEMENTOS EN MATRICES

Si en una matriz sólo pudiéramos almacenar contenidos, y leerlos de forma secuencial o a través de su clave, de poca utilidad nos resultaría. PHP permite buscar elementos en una matriz, determinando si existen o no. Observa buscarSimple.php:

La función in_array() recibe dos argumentos. El primero se refiere al valor que vamos a buscar. El segundo es el nombre de la matriz dónde buscarlo. Esta función devuelve true si el valor existe en la matriz, o false, en caso contrario. Además, podemos pasarle un tercer parámetro opcional, para que la búsqueda sea estricta. Así, por ejemplo, en el caso de la matriz de este último script, si probamos in_array(23, $valores); nos devolverá true, porque 23 está en la matriz. Sin embargo, si probamos in_array(23, $valores, true); (fijando a true el parámetro de búsqueda estricta), nos devolverá false, porque estamos buscando el valor numérico 23, y en la matriz este valor aparece como una cadena.

QUE ESTO NOS SIRVA DE LECCIÓN. PHP es un lenguaje de los que se conoce como débilmente tipado. Esto significa que es muy tolerante con respecto a los tipos de datos, como hemos visto en este ejemplo de la matriz. Eso es algo que a los programadores noveles les ayuda a introducirse en la programación, pero que los veteranos odiamos, porque es, en muchos casos, fuente de errores y, en el mejor de los casos, un síntoma de desorganización. Los creadores de PHP se dieron cuenta enseguida de esto, y preveyeron mecanismos para que PHP tenga la flexibilidad de un lenguaje no tipado pero, si es necesario y/o deseable, pueda comportarse como un lenguaje firmemente tipado. El tercer parámetro de la función in_array() es un ejemplo de esta doble posibilidad. A lo largo de sucesivos artículos veremos otras situaciones que nos ilustrarán en cómo hacer que PHP sea rígido con los tipos de datos.

En PHP contamos con otra forma de buscar un valor en una matriz. Se trata de la función array_search(). Funciona con los mismos parámetros que in_array() pero, si encuentra el valor buscado, en lugar de devolvernos true nos devuelve la clave del elemento correspondiente. Si no existe el valor buscado, nos devuelve false, igual que la función anterior.

Del mismo modo que podemos buscar un valor en una matriz, podemos también buscar una clave. Esto es útil en muchas ocasiones con matrices asociativas. Mira el script buscarClave.php.

La función array_key_exists() recibe una expresión y el nombre de una matriz y determina si la expresión es clave en alguno de los elementos de la matriz (vamos, si la clave existe en la matriz, como el propio nombre de la función nos dice de forma muy clara). En el ejemplo mostrado,devuelve true, cómo puedes comprobar cuando lo cargues.

Las matrices dan mucho más de sí. PHP es muy potente para el manejo de estas colecciones de datos, lo que facilita muchísimo la vida del programador. Sin embargo, este artículo es ya un poco largo, así que seguiremos hablando de matrices en posteriores artículos.

     

3 comentarios:

  1. Un artículo muy interesante e ilustrativo. Muchas gracias José por compartir tu sabiduría con el resto de los mortales.

  2. Pingback: Ordenar matrices multidimensionales en PHP » Recursos para programadores

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *