Recorrer array multidimensional recursivamente

A veces tenemos que tartar con arrays multidimensionales que son bastante complicados en su estructura, por lo que tenemos que empezar a escribir foreach’s anidados como locos, con la consecuencia inmediata de bajar la eficiencia de nuestros scripts y de disminuir la legibilidad de nuestro código.

Vamos a ver como mejorar estos inconvenientes usando una función recursiva.
Supongamos que tenemos el siguiente array:

Como podemos ver es bastante complicado en su estructura, por lo que utilizar foreach anidados para recuperar los datos sería un dolor de cabeza; además, para diferentes estructuras deberíamos reescribir el código para recorrerla.
Veríamos algo como lo siguiente:

La clave del asunto es ver este tipo de arrays como si fueran grafos (ver teoría de grafos) y de esta manera crear una función recursiva que use algún algoritmo conocido para recuperar los valores.

Veamos la función:

Esta función recorre el array completamente sin importar lo intrincado de su estructura, además, es muy eficiente y la lectura del código es muy simple, también es una solución genérica y reusable.

GD Star Rating
loading...
Recorrer array multidimensional recursivamente, 9.3 out of 10 based on 27 ratings

Related Posts

27 Comments

  1. mondobizarro
    Agosto 31, 2011 at 3:05 pm

    esta funcion es increible. muchas gracias!

  2. pablo
    Febrero 14, 2012 at 12:30 am

    Excelente, gracias

  3. Gonzalo
    Febrero 14, 2012 at 5:47 am

    Hola, una pregunta (Lo busque por toda la web), ¿Qué significa el operador “=>”?
    Gracias y salu2.

  4. Juan Benitez
    Febrero 16, 2012 at 10:31 am

    Hola Gonzalo, el operador “=>” sirve para diferenciar la clave y el valor de un elemento de una array. Por ejemplo, al crear un array puedo hacerlo indicando cuales serán sus claves y valores:

    Además, lo puedes usar en la sentencia “foreach” con el mismo propósito:

    Ejemplo completo:

    Salida:

  5. Gonzalo
    Febrero 17, 2012 at 6:21 am

    Muchas gracias y más por esos buenos ejemplos…Hacía bastante tenía la duda y Google no sirve para buscar símbolos.

  6. Carlos
    Septiembre 13, 2012 at 9:58 am

    Fantástico, gracias

  7. Jaume
    Octubre 19, 2012 at 8:00 am

    Muy buena funcion! me gusta 😉

  8. guduchango
    Enero 21, 2013 at 4:20 pm

    Que grande amigo, sos un groxo…!!! me solucionaste un problemon no me podia ir sin comentar….!!!! saludos

  9. Diego
    Febrero 17, 2013 at 11:42 am

    BUEN DIA CHICOS , NECESITO REALIZAR UN EJERCIO, DE LIQUIDACION DE SUELDOS.
    TENGO EL SIGUIENTE CODIGO

    Liquidacion de sueldos

    Emplados
    Horas
    Sueldos

    <?php

    // creamos los array correspondientes para empleados

    $empleados = array (
    array('Mendez','150','1500'),
    array('Gomez','190','1900'),
    array('Ramirez','250','2500'),
    array('Martinez','300','3000'),
    );

    foreach ($empleados as $empleado) {
    foreach ($empleado as $campo)
    echo "$campo””;

    echo ”;
    }

    ?>

    LA PREGUNTA ES ALGUIEN ME PUEDE AYUDAR, POR QUE NO ME QUEDA BIEN, LA IDEA ES HACER UNA TABLA QUE TENGA NOMBRE-HORAS-SUELDOS Y ABAJO DE TODO LOS TOTALES , CUALQUIER AYUDA SIRVE MUCHO ,., GRACIASSSSSSSSSSSSS

  10. Juan
    Febrero 18, 2013 at 10:18 pm

    Bueno veamos si esto te sirve:

  11. carlos
    Agosto 7, 2013 at 11:41 pm

    Me salvaste la chamba! thx!

  12. Francisco
    Agosto 20, 2013 at 3:17 pm

    Muchas gracias me sirvio muchisismo esta bastante sensillo y practico.

  13. jazmin
    Octubre 22, 2013 at 7:09 pm

    Hola, he leido sus comentario y espero puedan ayudarme, tengo un problema lo que quiero hacer es no insertar un registro en una fecha y horas ya ocupados. en mi base de datos guardo todo en una tabla… el siquiente código solo es el de la comparación que tengo, me compara las horas pero si tengo mas de un registro con la misma fecha ya no funciona, solo hace la comparación con el primero. Como podria realizar la comparación para que me compare todos los registros que tienen la misma fecha.

    <?php

    include (\"conexion.php\");

    //Datos del salon
    $salon_php=$_POST[\"salon_php\"];
    $nombre_evento=$_POST[\"nombre_evento\"];
    $apepat_resp=$_POST[\"apepat_resp\"];
    $apemat_resp=$_POST[\"apemat_resp\"];
    $nombre_resp=$_POST[\"nombre_resp\"];
    $fecha=$_POST[\"fecha\"];
    $hora_inicio=$_POST[\"hora_inicio\"];
    $hora_fin=$_POST[\"hora_fin\"];

    $query=\"SELECT * FROM tbl_evento where fecha = \’$fecha\’\";
    $result=mysql_query($query,$conexion) or die(\"Error: \".mysql_error());
    $Rs=mysql_fetch_array($result);
    $Rc=mysql_num_rows($result);

    echo $Rc;
    for($i=0;$i<$Rc;$i++)
    {
    if(($Rs[\"id_salon\"]!= $salonFin) && (($hora_inicio < $Rs[\"hora_inicio\"] && $hora_fin <= $Rs[\"hora_inicio\"]) || ($hora_inicio >= $Rs[\"hora_fin\"] && $hora_fin > $Rs[\"hora_fin\"])))
    {
    echo \"horario libre\";

    }
    else
    {
    echo \"horario ocupado\";

    }

    }

    ?>

  14. Luis
    Noviembre 11, 2013 at 4:02 pm

    Capazo..¡¡ gracias broo.. al fin pude entender bien sobre los arrays multidimensionales..¡¡ (Y)

  15. Sebastian
    Febrero 24, 2014 at 2:01 pm

    Buen Dia Juan..

    Gracias por este codigo, esta muy bueno. Te tengo una pregunta para ver si me puedes dar una mano.

    usando tu codigo
    function recorro($matriz)
    {

    foreach($matriz as $key=>$value){

    if (is_array($value)){
    //si es un array sigo recorriendo
    echo ‘key:’. $key;
    echo ”;
    recorro($value);
    }else{
    //si es un elemento lo muestro
    echo $key.’: ‘.$value ;
    echo ”;
    }

    }

    }

    en esta parte de codigo yo tengo un condicional que me funciona bien lo que necesito es que si la condicion del condicional se cumple tengo que sustituir el valor de la KEY con el nuevo valor y que este nuevo valor se quede grabado en el array.

    como lo puedo hacer???

  16. Juan
    Febrero 24, 2014 at 7:19 pm

    Hola Sebastián, no logro comprender exactamente qué precisas, tal vez si envías un ejemplo pueda ayudarme.
    saludos, Juan.

  17. Sebastian
    Febrero 25, 2014 at 9:33 am

    Hola Juan, gracias por contestar.

    te explico. tengo un array PHP que se llama form, este array es multidimencional y por eso me va muy bien tu codigo porque el array es dinamico es decir, segun la llamada a la base de dato va a tener informacion distinta.

    Nosotros tenemos la exigencia que ciertos valores en este array dedan tener la traduccion a segun del usuario que se conecta con la aplicacion. por esto hice la funcion extracttag, que en realidad lo que hace es recibir el valor de la key que lee tu foreach y lo busca en un archivo xml donde tengo la traducción del idioma del usuario.

    tu funcion me funciona perfectamente, lo que hice fue agregar un IF donde compruebo que el valor de la Key en el punto donde esta el foreach se encuentre en el archivo xml del lenguage del usuario si se encuentra entonce deberia cambiarme el valor en el array que el forearh me esta leyendo

    aqui abajo el codigo

    <?php
    $userlang = //codigo script que busca en la base de datos la informacion del idioma del usuario…..

    $form[0] = $base; //array php
    $form[1] = $array1; //array php
    $form[2] = $array2; //array php

    function extracttag($namefile, $name)
    {
    $file1 = $namefile.\".xml\";
    $file2 = $namefile.\".xml\";
    if (file_exists($file1))
    {
    $newtag = simplexml_load_file($file1);
    if ($newtag) {
    foreach ($newtag->tag as $a) {
    if ($a->tag_l == $name) {
    return $a->translations;
    }
    }
    return $a;
    } else return \"\";
    }
    elseif (file_exists($file2))
    {
    $newtag = simplexml_load_file($file2);
    if ($newtag) {
    foreach ($newtag->tag as $a) {
    if ($a->tag_l == $name) {
    return $a->translations;
    }
    }
    return $a;
    } else return \"\";
    } else
    {
    echo \"Error_open_xml\";
    }
    }

    function recorro($matriz)
    {
    foreach($matriz as $key=>$value)
    {
    if (is_array($value))
    {
    //si es un array sigo recorriendo
    recorro($value);
    }else
    {
    //si es un elemento lo muestro
    $tagvalue = extracttag($userlang, $value);
    if ($tagvalue != \"\"){$value = $tagvalue; $matriz[$key] = $tagvalue; }
    }
    }return($matriz);
    }

    recorro($form);

    echo \'<pre>\’; // Esto para que sea mas legible
    var_dump($form);
    echo \'</pre>\’;

  18. Juan
    Febrero 25, 2014 at 10:04 pm

    Sebastián, ahora si esta claro, una forma de hacerlo es cambiar la función recorro() para que reciba el parámetro por referencia, de esta manera vamos modificando la matriz dentro de la función y evitamos el return que ocasiona que se “corte” el recorrido del array.
    Prueba con esta versión de la función:

    Espero que te sirva.
    saludos, Juan.

  19. Sebastian
    Febrero 26, 2014 at 8:42 am

    Te mereces una estatua en la principal plaza de tu ciudad. Yo había probado usar referencia pero en el foreach, no se me ocurrió hacerlo en la función.

    Una cosita mas, el valor que me pone cuando se cumple la función if($tagvalue!=””){ $matriz[$key]=$tagvalue;} es el siguiente:

    [“tooltip”]=> object(SimpleXMLElement)#8 (1)
    {[0]=> string(26) “test,test,test,test,test, ” }

    yo necesito que el valor sea asi:
    [“tooltip”]=> string(26) “test,test,test,test,test, ”

    No se porque se trae el objeto XML completo.

    De nuevo Gracias,,

  20. Juan
    Febrero 27, 2014 at 8:08 pm

    Bueno, en ese caso parece ser la forma en que accedes a los elementos del XML, deberías leer la documentación de SimpleXml para hacerlo correctamente.
    De todas formas, si quieres enviame el XML que usas y te doy una mano.

    saludos, Juan.

  21. sebastian
    Febrero 28, 2014 at 8:05 am

    De nuevo Juan Muchas gracias por tu aporte.

    aqui te dejo mi codigo

    con esta funcion php traigo el contenido de la etiqueta translations de mi archivo XML

    function extracttag($namefile, $name)
    {
    $file1 = $namefile.”.xml”;
    if (file_exists($file1))
    {
    $newtag = simplexml_load_file($file1);

    if ($newtag)
    {
    foreach ($newtag->tag as $a)
    {
    if ($a->tag_l == $name)
    {
    return $a->translations;
    }
    }
    return $a;
    } else return “”;
    }
    else
    {
    echo “Error_open_xml”;
    }
    }

    y este es el contenido del archivo xml (puse solo unas cuantas tag para no hacer largo el comentario)

    Geolocation Lattest,test,test,test,test,
    Geolocation LongGeolocation LongGeolocation LongGeolocation LongGeolocation Long
    Site Name*Site Name*Site Name*Site Name*Site Name*Site Name*

  22. Jonatan
    Marzo 26, 2014 at 8:52 am

    ¿Cómo pdría utilizar la función recursiva recorro($matriz) para ir insertando los registros en la BD?
    EL Problema es que recibo de un webservice un array asoativo multidimensional. Ejemplo:
    Array
    ([0] => Array ([IDMarca =>82 …….)
    [1] => Array ([IDMarca =>82 …….)
    )….
    En la función recorro si el elemento es array vuelvo a recorrerlo. Si voy guardando en un array los valores, voy guardando los valores de todas los arrays, y no podría diferenciar los registros que quiero insertar en la BD.
    No sé si me he explicado bien.
    Gracias.

    Un saludo

  23. Juan
    Marzo 26, 2014 at 9:22 pm

    Hola, es claro que si tu array tiene 1 solo nivel no vale la pena usar la función recursiva ya que con un foreach simple se soluciona, digo esto porque el ejemplo que pones pareciera ser solo 1 nivel…
    Para más de 1 nivel habría que ver un ejemplo de tus datos más completo; para decidir de que forma cargamos los datos para un futuro INSERT.
    saludos, Juan.

  24. Jonatan Ortiz Salas
    Marzo 27, 2014 at 5:33 am

    Buenos días!
    No mi array es multidimensional variable.
    A ver pongo un ejemplo más claro.
    Realizo una llamada a un webservice y me devuelve un objeto StdClass. Utilizo una función objetToArray($array) que me convierte el objeto a un array multidimensional.
    El array multidimensional puede ser por ejemplo:
    Array
    (
    [0] => Array
    (
    [IDModelYear] => 1
    [ModelYear] => 1990
    [Versiones] => Array
    (
    [0] => Array
    (
    [IDVersion] => 463
    [Descripcion] => hola
    [Foto] => foto.jpg
    )
    [1] => Array
    (
    [IDVersion] => 464
    [Descripcion] => hola2
    [Foto] => foto
    )


    [1] => Array
    (
    [IDModelYear] => 1
    [ModelYear] => 2000
    [Versiones] => Array
    (
    [0] => Array
    (
    [IDVersion] => 279
    [Descripcion] => ejemplo
    [Foto] => foto.jpg
    )
    [1] => Array
    (
    [IDVersion] => 280
    [Descripcion] => ejemplox
    [Foto] => fotoy.jpg
    )

    Pues bien necesito ir recorriendo este array multidimensional asociativo e insertando registros en la Base de Datos.
    Los campos de la tabla serían:
    IDModelYear ModelYear IDVersion Descripcion Foto
    1 1990 463 hola foto.jpg
    1 1990 464 hola2 foto
    1 2000 279 ejemplo foto.jpg
    1 2000 280 ejemplox fotoy.jpg

    Básicamente, esto sería lo que quiero implementar. No sé como podría utilizar/modificar la función recursiva recorro para poder implementar lo que te comenta.

    Muchísimas gracias por adelantado.
    Perdone las molestias.

  25. Christian Altuve
    Julio 28, 2014 at 12:51 am

    Buenas! De verdad necesito una ayuda super inmensa, ya no se que hacer y estoy desesperado. Estoy realizando un sistema de inscripción, pero no logro que me cargue la sección que selecciono para “X” materia, me guarda una en blanco so simplemente me repite “N” veces la seccion de la materia con todas las materias seleccionadas.

    Aquí pongo el código del formulario donde el estudiante escoge la(s) materia(s):

    SELECCIONA LA(S) MATERIAS A CURSAR EN EL PERÍODO CONFIGURADO

    Código

    Materia

    Créditos

    Seccion

    <input name="tag[]" type="checkbox" value="” onclick=”Block(this,’Aukera’)” id=”txek”/>

    ‘0’”);
    while ($row1=mysql_fetch_array($result2))
    {

    echo “”.$row1[‘sec’].””;

    }
    mysql_free_result($result2)
    ?>

    RECUERDA QUE PARA EL PERÍODO INTENSIVO SÓLO SE PERMITE UN MÁXIMO DE 12 U.C.

    Y por este lado recojo la información y la inserto en mi tabla

    <?php
    mysql_connect("localhost","******","*******") or die("No se pudo conectar a la base de datos");

    //SELECCIONAMOS LA BASE DE DATOS CON LA CUAL VAMOS A TRABAJAR CAMBIEN EL VALOR POR LA SUYA
    mysql_select_db("******");{

    foreach($_POST['tags'] as $valor1)
    foreach($_POST['tag'] as $valor)
    {
    $qry = mysql_query("INSERT INTO inscripcion (lapso, sec, materia, exp) VALUES ('2014-I','".$valor1."', '".$valor."', '".$_SESSION['exp']."')") or die("Query: $qry Error: “.mysql_error());
    }
    }?>

    si podrian ayudarme, necesito que el sistema inscriba para el día miercoles.
    Ayudaaaa!!

  26. Kalimero
    Marzo 3, 2016 at 9:28 am

    Hola.

    Intento crear un array recursivo del plan general contable. De forma que todas las cuentas de capital (1) sean a su vez arrays en forma de árbol del plan.

    alguna idea?

  27. Juan
    Marzo 8, 2016 at 12:32 am

    Hola Kalimero, disculpa pero no entiendo de que me hablas… que son las cuentas de capital????

  28. Alejandro
    Octubre 15, 2016 at 9:00 pm

    Disculpa quisiera tu ayuda como puedo hacer cuando inserto un dato por input a php compararlo con un valor dentro de este array

    array('carro' => 'puerta','caucho','parachoque', 'avion'=>'aleron','cola','alas', 'casa'=>'cocina','comedor','ventana', 'bicicleta'=>'pedales','cadena','frenos', 'supermercado'=>'anaqueles','carritos','caja', 'equipo'=>'volumen','cd','cornetas'); 

    y mostrar a que pertenece por ejemplo si escribo puerta me siga que esta en carro

     

    muchas gracias de antemano

Leave A Comment

Security Code:

Leer más
Como extender Smarty mediante plugins con PHP
Como extender Smarty mediante plugins con PHP

En este artículo vamos ver cómo extender el famoso y conocido motor de plantillas (o template engine) Smarty mediante plugins...

Cerrar