How to implode foreach
Asked Answered
A

6

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.

Amice answered 2/9, 2010 at 10:55 Comment(2)
Mmh what is the point in having a lot of links with different names but the same URL?Empyreal
Felix, are you a mind reader who can see what's behind "//do something"? :-)Clayborne
D
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);
Dodgson answered 2/9, 2010 at 10:59 Comment(5)
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[] = "<a href=\"$url\" title=...Fancyfree
This one's slower though and is neither more readable nor functional. (not that it's worse, I'm just defending the micro-optimization)Kovacs
@Blixt, that's just a guess, I can't find the source, but concat and substr was benchmarked to be faster in all cases.Kovacs
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.Fancyfree
Bingo McBingo, did the trick for me, simplest way to get that darned comma in to an existing foreach loopPoulos
H
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>';
}));
Hugues answered 2/9, 2010 at 11:1 Comment(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.Kovacs
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).Empyreal
Isn't this far more complicated than necessary?Concourse
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.Hugues
R
3
$first = TRUE;
foreach($names as $name) {
    //do something
    if(!$first) { echo ', '; }
    $first = FALSE;
    echo '<a href="', $url, '" title="', $title, '">', $name, '</a>';
}
Reprehensible answered 2/9, 2010 at 11:0 Comment(1)
Micro-optimisation: with echo, use commas instead of string concatenation: electrictoolbox.com/php-echo-commas-vs-concatenationSeve
K
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.

Kovacs answered 2/9, 2010 at 10:56 Comment(5)
why, this is faster than implode.Kovacs
… until you change the separator and forget to adjust the substr.Furniture
@Furniture that's very valid. Not a reason to give me a minus though :/Kovacs
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 substring it into syntax errordom. I am trying to discourage this approach when there is a cleaner way with implode.Furniture
@reinis, wtf are you even talking about? >So use the foreach method unless performance is absolutely critical. Please recall the downvote.Kovacs
C
2
$s = '';
foreach ($names as $name) {
  if ($s) $s .= ', ';
  $s .= '<a href="' . $url . '" title="' . $title . '">' . $name . '</a>';
}
Concourse answered 2/9, 2010 at 11:3 Comment(5)
i think you meant if(!$s), or better if(strlen($s) == 0) $s = ', ';Reprehensible
knittl, you can save a function call by checking isset($s[0]) instead of strlen \o/Clayborne
No. if ($s) is correct. We don't want to start with a comma. We want to add one only from the second link on.Concourse
But you managed to confuse me enough to edit my answer and then revert it.Concourse
oh ok, i didn't realize you were using $s for both the delimiter and the string itself. sorry for the caused confusionReprehensible
R
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>';
 }
Rule answered 2/9, 2010 at 10:58 Comment(1)
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 ...)...Sowers

© 2022 - 2024 — McMap. All rights reserved.