5

How to implode foreach() with comma?

foreach($names as $name) {
    //do something
    echo '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
}

Want to add comma after each link, except the last one.

James
  • 42,081
  • 53
  • 136
  • 161

6 Answers6

26

Raveren's solution is efficient and beautiful, but here is another solution too (which can be useful in similar scenarios):

$elements = array();
foreach($names as $name) {
    //do something
    $elements[] = '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
}
echo implode(',', $elements);
Emil Vikström
  • 90,431
  • 16
  • 141
  • 175
  • 2
    In general, this one should be faster than concatenating strings. This would probably be even faster if the string was built using either string formatting or variable substitution: `$elements[] = " – Blixt Sep 02 '10 at 11:03
  • This one's slower though and is neither more readable nor functional. (not that it's worse, I'm just defending the micro-optimization) – raveren Sep 02 '10 at 11:04
  • @Blixt, that's just a guess, I can't find the source, but concat and substr was benchmarked to be faster in all cases. – raveren Sep 02 '10 at 11:09
  • True, it's just a guess, but generally, string formatting is more elegant too, so I wouldn't consider it a bad change even if it was slower. Also, an array of strings that is concatenated is, to me, more readable than stripping off the last character. – Blixt Sep 02 '10 at 11:20
  • Bingo McBingo, did the trick for me, simplest way to get that darned comma in to an existing foreach loop – Jake Rayson Jan 14 '14 at 16:29
12

You need to transform your array instead of iterating using foreach. You can do this with array_map.

PHP 5.3 syntax with closures

echo implode(", ", array_map(function($name) use($url, $title)
{
    return '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
}, $names));

Compatible syntaxe before PHP 5.3

function createLinkFromName($name)
{
    return '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
}
echo implode(", ", array_map('createLinkFromName', $names));

PHP 5.3 syntax with a better reability

function a_map($array, $function)
{
    return array_map($function, $array);
}

echo implode(", ", a_map($names, function($name) use($url, $title)
{
    return '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
}));
Vincent Robert
  • 35,564
  • 14
  • 82
  • 119
  • 4
    Frankly this borders on unreadable - especially with such a trivial task. Also it's most probably the slowest solution if you're into performance. – raveren Sep 02 '10 at 11:06
  • 1
    I wanted to propose the same, but you have to be careful with `$url` and `$title`. They won't be set (at least in the before PHP 5.3 example). – Felix Kling Sep 02 '10 at 11:07
  • 7
    Isn't this far more complicated than necessary? – TRiG Sep 02 '10 at 11:35
  • It is not that complicated, unreadability comes from the array_map syntax that puts the function first which is not a wise decision when working with closures. I suggest defining a new function with the opposite order of arguments to improve readbility. – Vincent Robert Sep 02 '10 at 15:14
3
$first = TRUE;
foreach($names as $name) {
    //do something
    if(!$first) { echo ', '; }
    $first = FALSE;
    echo '<a href="', $url, '" title="', $title, '">', $name, '</a>';
}
knittl
  • 246,190
  • 53
  • 318
  • 364
  • Micro-optimisation: with echo, use commas instead of string concatenation: http://www.electrictoolbox.com/php-echo-commas-vs-concatenation/ – Douglas Sep 02 '10 at 11:13
2
foreach($names as $name) {
    //do something
    $str .= '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>,';
}
echo substr($str,0,-1);

EDIT: as the comments point out, this way of doing things is a little error prone if you change the separator (precisely its length) and forget the substr parameter. So use the foreach method unless performance is absolutely critical.

raveren
  • 17,799
  • 12
  • 70
  • 83
  • why, this is faster than implode. – raveren Sep 02 '10 at 11:02
  • 4
    … until you change the separator and forget to adjust the `substr`. – janmoesen Sep 02 '10 at 11:03
  • @janmoesen that's very valid. Not a reason to give me a minus though :/ – raveren Sep 02 '10 at 11:10
  • 1
    Sorry, I was not giving you specifically a minus; just this approach. I've seen it too many times: building a query this way and then `substr`ing it into syntax errordom. I am trying to discourage this approach when there is a cleaner way with `implode`. – janmoesen Sep 02 '10 at 11:11
  • @reinis, wtf are you even talking about? `>So use the foreach method unless performance is absolutely critical.` Please recall the downvote. – raveren Sep 02 '10 at 13:17
2
$s = '';
foreach ($names as $name) {
  if ($s) $s .= ', ';
  $s .= '<a href="' . $url . '" title="' . $title . '">' . $name . '</a>';
}
TRiG
  • 10,148
  • 7
  • 57
  • 107
1

Here is an ugly solution using echo:

 $total = (count($names) - 1 );

 foreach($names as $i => $name) 
 {
      if($i != $total) 
           echo '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>, ';
      else
           echo '<a href="' . $url . '" title="' . $title . '">' . $name .'</a>';
 }
Jake N
  • 10,535
  • 11
  • 66
  • 112
  • 2
    I would +1, except that counting the array on every iteration is quite wasteful (especially if the array is sizable)... Perhaps pre-compute (`$numOfElements = count($names) - 1; foreach ...`)... – ircmaxell Sep 02 '10 at 11:46