在php中循环一个多维数组

时间:2021-11-03 10:48:30

I have a multidimensional array like this:

我有一个像这样的多维数组:

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"
          }
        }
      }
    }
  }
}

I would like to make html output like this:

我想像这样制作html输出:

--

-

EVENT 1
ARTIST 1
artist 1 desc
http://www.artist1.com, http://www.artist1-2.com

EVENT 1 ARTIST 1艺术家1 desc http://www.artist1.com,http://www.artist1-2.com

ARTIST 8
artist 8 desc
http://www.artist8.com

艺术家8艺术家8 desc http://www.artist8.com

ARTIST 5
artist 5 desc
http://www.artist5.com

艺术家5艺术家5 desc http://www.artist5.com

--

-

EVENT 2
ARTIST 76
artist 76 desc
http://www.artist76.com

EVENT 2 ARTIST 76艺术家76 desc http://www.artist76.com

ARTIST 4
artist 4 desc
http://www.artist4.com

艺术家4艺术家4 desc http://www.artist4.com

--

-

etc.

等等

I'm confused about digging deeper and deeper in arrays, especially when my array keys are not sequential numbers but IDs of artist/link/etc.
These arrays will kill me, honestly! =)

我对在数组中越来越深入挖掘感到困惑,特别是当我的数组键不是序列号而是艺术家/链接/等的ID时。老实说,这些阵列会杀了我! =)

Thanks for any help in advance!!!

在此先感谢您的帮助!!!

3 个解决方案

#1


11  

You're best using the foreach construct to loop over your array. The following is untested and is off the top of my head (and probably therefore not as thought through as it should be!) but should give you a good start:

你最好使用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);
  }
}

#2


7  

The foreach statement will take care of all of this for you, including the associative hashes. Like this:

foreach语句将为您处理所有这些,包括关联哈希。喜欢这个:

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

        }
        /* etc */
    }
}

#3


5  

I think a good way to approach this is "bottom up", ie. work out what to do with the inner-most values, then use those results to work out the next-level-up, and so on until we reach the top. It's also good practice to write our code in small, single-purpose, re-usable functions as much as possible, so that's what I'll be doing.

我认为解决这个问题的好方法是“自下而上”,即。弄清楚如何处理最内层的值,然后使用这些结果来计算下一级,依此类推,直到我们达到顶峰。将代码尽可能地编写在小型,单用途,可重用的函数中也是一种很好的做法,这就是我将要做的事情。

Note that I'll assume your data is safe (ie. it's not been provided by a potentially-malicious user). I'll also assume that the keys "ime" and "opi" are meant to match the "name" and "description" of the other arrays ;)

请注意,我假设您的数据是安全的(即,它不是由潜在恶意用户提供的)。我还假设键“ime”和“opi”用于匹配其他数组的“名称”和“描述”;)

We can ignore the innermost strings themselves, since we don't need to modify them. In that case the inner-most structure I can see are the individual links, which are arrays containing a 'URL' value. Here's some code to render a single link:

我们可以忽略最里面的字符串本身,因为我们不需要修改它们。在这种情况下,我能看到的最内层结构是各个链接,它们是包含“URL”值的数组。这是一些呈现单个链接的代码:

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

This has reduced an array down to a string, so we can use it remove the inner-most layer. For example:

这将数组缩减为字符串,因此我们可以使用它删除最内层。例如:

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

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

Now we move out a layer to the 'links' arrays. There are two things to do here: apply "render_link" to each element, which we can do using "array_map", then reduce the resulting array of strings down to a single comma-separated string, which we can do using the "implode" function:

现在我们将一个图层移出到'links'数组。这里有两件事要做:对每个元素应用“render_link”,我们可以使用“array_map”进行操作,然后将生成的字符串数组减少到一个以逗号分隔的字符串,我们可以使用“implode”功能:

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

This has removed another layer, for example:

这已删除了另一个图层,例如:

// 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>"

Now we can go out another level to an individual artist, which is an array containing 'name', 'description' and 'links'. We know how to render 'links', so we can reduce these down to a single string separated by linebreaks:

现在,我们可以将另一个级别转到单个艺术家,这是一个包含“名称”,“描述”和“链接”的数组。我们知道如何渲染“链接”,因此我们可以将它们减少到由换行符分隔的单个字符串:

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);
}

This has removed another layer, for example:

这已删除了另一个图层,例如:

// 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>"

Now we can move out a layer to the 'artists' arrays. Just like when we went from a single link to the 'links' arrays, we can use array_map to handle the contents and implode to join them together:

现在我们可以将一个图层移出'艺术家'数组。就像我们从单个链接到“链接”数组一样,我们可以使用array_map来处理内容并将内部连接在一起:

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

This has removed another layer (no example, because it's getting too long ;) )

这已经删除了另一层(没有例子,因为它太长了;))

Next we have an event, which we can tackle in the same way we did for the artist, although I'll also remove the ID number and format the title:

接下来我们有一个事件,我们可以像对艺术家一样处理这个事件,虽然我也会删除ID号并格式化标题:

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);
}

Now we've reached the outer array, which is an array of events. We can handle this just like we did for the arrays of artists:

现在我们已经到达了外部数组,这是一个事件数组。我们可以像处理艺术家阵列一样处理这个问题:

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

You might want to stop here, since passing your array to render_events will give you back the HTML you want:

您可能想要停在这里,因为将数组传递给render_events将返回您想要的HTML:

echo render_events($my_data);

However, if we want more of a challenge we can try to refactor the code we've just written to be less redundant and more re-usable. One simple step is to get rid of render_links, render_artists and render_events since they're all variations on a more-general pattern:

但是,如果我们想要更多挑战,我们可以尝试重构我们刚刚编写的代码,以减少冗余和更多可重用。一个简单的步骤是摆脱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);

If this is part of a larger application, we may want to tease out some more general patterns. This makes the code slightly more complex, but much more re-usable. Here are a few patterns I've spotted:

如果这是更大的应用程序的一部分,我们可能想要梳理一些更一般的模式。这使代码稍微复杂一些,但可重用性更高。以下是我发现的一些模式:

// 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);

#1


11  

You're best using the foreach construct to loop over your array. The following is untested and is off the top of my head (and probably therefore not as thought through as it should be!) but should give you a good start:

你最好使用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);
  }
}

#2


7  

The foreach statement will take care of all of this for you, including the associative hashes. Like this:

foreach语句将为您处理所有这些,包括关联哈希。喜欢这个:

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

        }
        /* etc */
    }
}

#3


5  

I think a good way to approach this is "bottom up", ie. work out what to do with the inner-most values, then use those results to work out the next-level-up, and so on until we reach the top. It's also good practice to write our code in small, single-purpose, re-usable functions as much as possible, so that's what I'll be doing.

我认为解决这个问题的好方法是“自下而上”,即。弄清楚如何处理最内层的值,然后使用这些结果来计算下一级,依此类推,直到我们达到顶峰。将代码尽可能地编写在小型,单用途,可重用的函数中也是一种很好的做法,这就是我将要做的事情。

Note that I'll assume your data is safe (ie. it's not been provided by a potentially-malicious user). I'll also assume that the keys "ime" and "opi" are meant to match the "name" and "description" of the other arrays ;)

请注意,我假设您的数据是安全的(即,它不是由潜在恶意用户提供的)。我还假设键“ime”和“opi”用于匹配其他数组的“名称”和“描述”;)

We can ignore the innermost strings themselves, since we don't need to modify them. In that case the inner-most structure I can see are the individual links, which are arrays containing a 'URL' value. Here's some code to render a single link:

我们可以忽略最里面的字符串本身,因为我们不需要修改它们。在这种情况下,我能看到的最内层结构是各个链接,它们是包含“URL”值的数组。这是一些呈现单个链接的代码:

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

This has reduced an array down to a string, so we can use it remove the inner-most layer. For example:

这将数组缩减为字符串,因此我们可以使用它删除最内层。例如:

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

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

Now we move out a layer to the 'links' arrays. There are two things to do here: apply "render_link" to each element, which we can do using "array_map", then reduce the resulting array of strings down to a single comma-separated string, which we can do using the "implode" function:

现在我们将一个图层移出到'links'数组。这里有两件事要做:对每个元素应用“render_link”,我们可以使用“array_map”进行操作,然后将生成的字符串数组减少到一个以逗号分隔的字符串,我们可以使用“implode”功能:

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

This has removed another layer, for example:

这已删除了另一个图层,例如:

// 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>"

Now we can go out another level to an individual artist, which is an array containing 'name', 'description' and 'links'. We know how to render 'links', so we can reduce these down to a single string separated by linebreaks:

现在,我们可以将另一个级别转到单个艺术家,这是一个包含“名称”,“描述”和“链接”的数组。我们知道如何渲染“链接”,因此我们可以将它们减少到由换行符分隔的单个字符串:

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);
}

This has removed another layer, for example:

这已删除了另一个图层,例如:

// 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>"

Now we can move out a layer to the 'artists' arrays. Just like when we went from a single link to the 'links' arrays, we can use array_map to handle the contents and implode to join them together:

现在我们可以将一个图层移出'艺术家'数组。就像我们从单个链接到“链接”数组一样,我们可以使用array_map来处理内容并将内部连接在一起:

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

This has removed another layer (no example, because it's getting too long ;) )

这已经删除了另一层(没有例子,因为它太长了;))

Next we have an event, which we can tackle in the same way we did for the artist, although I'll also remove the ID number and format the title:

接下来我们有一个事件,我们可以像对艺术家一样处理这个事件,虽然我也会删除ID号并格式化标题:

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);
}

Now we've reached the outer array, which is an array of events. We can handle this just like we did for the arrays of artists:

现在我们已经到达了外部数组,这是一个事件数组。我们可以像处理艺术家阵列一样处理这个问题:

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

You might want to stop here, since passing your array to render_events will give you back the HTML you want:

您可能想要停在这里,因为将数组传递给render_events将返回您想要的HTML:

echo render_events($my_data);

However, if we want more of a challenge we can try to refactor the code we've just written to be less redundant and more re-usable. One simple step is to get rid of render_links, render_artists and render_events since they're all variations on a more-general pattern:

但是,如果我们想要更多挑战,我们可以尝试重构我们刚刚编写的代码,以减少冗余和更多可重用。一个简单的步骤是摆脱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);

If this is part of a larger application, we may want to tease out some more general patterns. This makes the code slightly more complex, but much more re-usable. Here are a few patterns I've spotted:

如果这是更大的应用程序的一部分,我们可能想要梳理一些更一般的模式。这使代码稍微复杂一些,但可重用性更高。以下是我发现的一些模式:

// 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);