Цикл многомерного массива в php - PullRequest
3 голосов
/ 12 октября 2009

У меня есть многомерный массив, подобный этому:

array(2) {
  [1]=>
  array(3) {
    ["eventID"]=>
    string(1) "1"
    ["eventTitle"]=>
    string(7) "EVENT 1"
    ["artists"]=>
    array(3) {
      [4]=>
      array(2) {
        ["name"]=>
        string(8) "ARTIST 1"
        ["description"]=>
        string(13) "artist 1 desc"
        ["links"]=>
        array(2) {
          [1]=>
          array(2) {
            ["URL"]=>
            string(22) "http://www.artist1.com"
          }
          [6]=>
          array(2) {
            ["URL"]=>
            string(24) "http://www.artist1-2.com"
          }
        }
      }
      [5]=>
      array(2) {
        ["name"]=>
        string(8) "ARTIST 8"
        ["description"]=>
        string(13) "artist 8 desc"
        ["links"]=>
        array(1) {
          [8]=>
          array(2) {
            ["URL"]=>
            string(22) "http://www.artist8.com"
          }
        }
      }
      [2]=>
      array(2) {
        ["ime"]=>
        string(8) "ARTIST 5"
        ["opis"]=>
        string(13) "artist 5 desc"
        ["links"]=>
        array(1) {
          [9]=>
          array(2) {
            ["URL"]=>
            string(22) "http://www.artist5.com"
          }
        }
      }
    }
  }
  [2]=>
  array(3) {
    ["eventID"]=>
    string(1) "2"
    ["eventTitle"]=>
    string(7) "EVENT 2"
    ["artists"]=>
    array(3) {
      [76]=>
      array(2) {
        ["name"]=>
        string(9) "ARTIST 76"
        ["description"]=>
        string(14) "artist 76 desc"
        ["links"]=>
        array(1) {
          [13]=>
          array(2) {
            ["URL"]=>
            string(23) "http://www.artist76.com"
          }
        }
      }
      [4]=>
      array(2) {
        ["name"]=>
        string(8) "ARTIST 4"
        ["description"]=>
        string(13) "artist 4 desc"
        ["links"]=>
        array(1) {
          [11]=>
          array(2) {
            ["URL"]=>
            string(22) "http://www.artist4.com"
          }
        }
      }
    }
  }
}

Я хотел бы сделать вывод html следующим образом:

-

СОБЫТИЕ 1
ХУДОЖНИК 1
художник 1 desc
http://www.artist1.com, http://www.artist1 -2.com

ХУДОЖНИК 8
художник 8 desc
http://www.artist8.com

ХУДОЖНИК 5
художник 5 desc
http://www.artist5.com

-

СОБЫТИЕ 2
ХУДОЖНИК 76
художник 76 desc
http://www.artist76.com

ХУДОЖНИК 4
художник 4 desc
http://www.artist4.com

-

и т.д.

Меня смущает копание глубже и глубже в массивах, особенно когда мои ключи массива не последовательные числа, а идентификаторы исполнителя / ссылки / и т. Д.
Эти массивы убьют меня, если честно! =)

Заранее спасибо за любую помощь !!!

Ответы [ 3 ]

11 голосов
/ 12 октября 2009

Лучше всего использовать конструкцию foreach для циклической обработки массива Следующее не проверено и находится вне моей головы (и, вероятно, поэтому не настолько продуманно, как должно быть!), Но должно дать вам хорошее начало:

foreach ($mainArray as $event)
{
  print $event["eventTitle"];

  foreach ($event["artists"] as $artist)
  {
     print $artist["name"];
     print $artist["description"];

     $links = array();
     foreach ($artist["links"] as $link)
     {
       $links[] = $link["URL"];
     }
     print implode(",", $links);
  }
}
8 голосов
/ 12 октября 2009

Оператор foreach позаботится обо всем этом для вас, включая ассоциативные хеши. Как это:

foreach($array as $value) {
    foreach($value as $key => $val) {
        if($key == "links") {

        }
        /* etc */
    }
}
5 голосов
/ 27 июня 2014

Я думаю, что хороший способ подойти к этому "снизу вверх", т.е. определите, что делать с самыми внутренними ценностями, затем используйте эти результаты для разработки следующего уровня и так далее, пока мы не достигнем вершины. Хорошей практикой также является написание нашего кода в небольших одноцелевых, многократно используемых функциях, насколько это возможно, поэтому я буду этим заниматься.

Обратите внимание, что я предполагаю, что ваши данные в безопасности (т.е. они не были предоставлены потенциально злонамеренным пользователем). Я также предполагаю, что ключи «ime» и «opi» предназначены для соответствия «name» и «description» других массивов;)

Мы можем игнорировать самые внутренние строки, так как нам не нужно их изменять. В этом случае самой внутренней структурой, которую я вижу, являются отдельные ссылки, которые представляют собой массивы, содержащие значение «URL». Вот некоторый код для рендеринга одной ссылки:

function render_link($link) {
  return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}

Это уменьшило массив до строки, поэтому мы можем использовать его для удаления самого внутреннего слоя. Например:

// Input
array('URL' => "http://www.artist1.com")

// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>"

Теперь мы перемещаем слой в массивы 'links'. Здесь нужно сделать две вещи: применить «render_link» к каждому элементу, что мы можем сделать с помощью «array_map», затем уменьшить полученный массив строк до одной строки, разделенной запятыми, что мы можем сделать с помощью «implode» функция:

function render_links($links_array) {
  $rendered_links = array_map('render_link', $links_array);
  return implode(', ', $rendered_links);
}

Это позволило удалить другой слой, например:

// Input
array(1 => array('URL' => "http://www.artist1.com"),
      6 => array('URL' => "http://www.artist1-2.com"))

// Output
"<a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"

Теперь мы можем перейти на другой уровень к отдельному исполнителю, который представляет собой массив, содержащий «имя», «описание» и «ссылки». Мы знаем, как отображать «ссылки», поэтому мы можем свести их к одной строке, разделенной переносами строк:

function render_artist($artist) {
  // Replace the artist's links with a rendered version
  $artist['links'] = render_links($artist['links']);

  // Render this artist's details on separate lines
  return implode("\n<br />\n", $artist);
}

Это позволило удалить другой слой, например:

// Input
array('name'        => 'ARTIST 1',
      'description' => 'artist 1 desc',
      'links'       => array(
         1          => array(
           'URL'    => 'http://www.artist1.com')
         6          => array(
           'URL'    => 'http://www.artist1-2.com')))

// Output
"ARTIST 1
 <br />
 artist 1 desc
 <br />
 <a href='http://www.artist1.com'>http://www.artist1.com</a>, <a href='http://www.artist1-2.com'>http://www.artist1-2.com</a>"

Теперь мы можем переместить слой в массивы 'художников'. Точно так же, как когда мы переходили от одной ссылки к массиву 'links', мы можем использовать array_map для обработки содержимого и взрыва, чтобы объединить их вместе:

function render_artists($artists) {
  $rendered = array_map('render_artist', $artists);
  return implode("\n<br /><br />\n", $rendered);
}

Это удалило еще один слой (без примера, потому что он становится слишком длинным;))

Далее у нас есть событие, которое мы можем выполнить так же, как мы делали для художника, хотя я также удалю идентификационный номер и отформатирую заголовок:

function render_event($event) {
  unset($event['eventID']);
  $event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
  $event['artists']    = render_artists($event['artists']);
  return implode("\n<br />\n", $event);
}

Теперь мы достигли внешнего массива, который является массивом событий. Мы можем справиться с этим так же, как мы это делали для массивов художников:

function render_events($events) {
  $rendered = array_map('render_event', $events);
  return implode("\n<br /><br />--<br /><br />", $rendered);
}

Возможно, вы захотите на этом остановиться, поскольку передача массива в render_events вернет вам нужный HTML-код:

echo render_events($my_data);

Однако, если мы хотим больше проблем, мы можем попытаться реорганизовать код, который мы только что написали, чтобы он был менее избыточным и более пригодным для повторного использования. Один простой шаг - избавиться от render_links, render_artists и render_events, так как все они являются вариациями более общего шаблона:

function reduce_with($renderer, $separator, $array) {
  return implode($separator, array_map($renderer, $array));
}

function render_artist($artist) {
  $artist['links'] = reduce_with('render_link', ', ', $artist['links']);
  return implode("\n<br />\n", $artist);
}

function render_event($event) {
  unset($event['eventID']);
  $event['eventTitle'] = "<strong>{$event['eventTitle']}</strong>";
  $event['artists']    = reduce_with('render_artist',
                                     "\n<br /><br />\n",
                                     $event['artists']);
  return implode("\n<br />\n", $event);
}

echo reduce_with('render_event', "\n<br /><br />--<br /><br />", $my_data);

Если это часть более крупного приложения, мы можем захотеть выявить некоторые более общие закономерности. Это делает код немного более сложным, но гораздо более пригодным для повторного использования. Вот несколько образцов, которые я заметил:

// Re-usable library code

// Partial application: apply some arguments now, the rest later
function papply() {
  $args1 = func_get_args();
  return function() use ($args1) {
    return call_user_func_array(
      'call_user_func',
      array_merge($args1, func_get_args()));
  };
}

// Function composition: chain functions together like a(b(c(...)))
function compose() {
  $funcs = array_reverse(func_get_args());
  $first = array_shift($funcs);
  return function() use ($funcs, $first) {
    return array_reduce($funcs,
                        function($x, $f) { return $f($x); },
                        call_user_func_array($first, func_get_args()));
  };
}

// Transform or remove a particular element in an array
function change_elem($key, $func, $array) {
  if is_null($func) unset($array[$key]);
  else $array[$key] = $func($array[$key]);
  return $array;
}

// Transform all elements then implode together
function reduce_with($renderer, $separator) {
  return compose(papply('implode', $separator),
                 papply('array_map', $renderer));
}

// Wrap in HTML
function tag($tag, $text) {
  return "<{$tag}>{$text}</{$tag}>";
}

// Problem-specific code

function render_link($link) {
  return "<a href='{$link['URL']}'>{$link['URL']}</a>";
}

$render_artist = compose(
  papply('implode', "\n<br />\n"),
  papply('change_elem', 'links', papply('reduce_with',
                                        'render_link',
                                        ', '));

$render_event = compose(
  papply('implode', "\n<br />\n"),
  papply('change_elem', null,         'eventID'),
  papply('change_elem', 'eventTitle', papply('tag', 'strong')),
  papply('change_elem', 'artists',    papply('reduce_with',
                                             $render_artist,
                                             "\n<br /><br />\n")));

echo reduce_with($render_event, "\n<br /><br />--<br /><br />", $my_data);
...