tags:

views:

289

answers:

8

This is probably a simple question, but how do you iterate through an array, doing something to each one, until the last one and do something different?

I have an array of names. I want to output the list of names separated by commas.

Joe, Bob, Foobar

I don't want a comma at the end of the last name in the array, nor if there is only one value in the array (or none!).

Update: I can't use implode() because I have an array of User model objects where I get the name from each object.

$users = array();
$users[] = new User();

foreach ($users as $user) {
    echo $user->name;
    echo ', ';
}

How can I achieve this and still use these objects?

Update: I was worrying too much about how many lines of code I was putting in my view script, so I decided to create a view helper instead. Here's what I ended up with:

$array = array();
foreach($users as $user) {
    $array[] = $user->name;
}
$names = implode(', ', $array);
+6  A: 
$array = array('joe', 'bob', 'Foobar');
$comma_separated = join(",", $array);

output:

joe,bob,Foobar

BioBuckyBall
apparently join is an alias for implode :)
BioBuckyBall
I actually prefer the use of join because it doesn't confuse those coming from a java/perl background.
karim79
I know! Sadly, `split` is not an alias for `explode`. So in PHP I just use `explode` and `implode` as lame as the names are :)
Doug Neiner
thanks for your answer, unfortunately I can't use join() because the array contains objects. Is there a different way I can achieve the same thing?
Andrew
+14  A: 

Use implode:

$names = array('Joe', 'Bob', 'Foobar');
echo implode(', ', $names); # prints: Joe, Bob, Foobar

To clarify, if there is only one object in the array, the ', ' separator will not be used at all, and a string containing the single item would be returned.

EDIT: If you have an array of objects, and you wanted to do it in a way other than a for loop with tests, you could do this:

function get_name($u){ return $u->name; };
echo implode(', ', array_map('get_name', $users) ); # prints: Joe, Bob, Foobar
Doug Neiner
thanks for your answer, unfortunately I can't use implode() because the array contains objects. Is there a different way I can achieve the same thing?
Andrew
In PHP 5.3+ you don't even have to declare a function, just do it anonymously: implode(', ', array_map(function($user) { return $user->name; }, $users)
Jordan
Is it bad that I've been writing php for years and never thought of this?
Brendan Long
@Brendan, no its not. Its just when you work with PHP after using Ruby, you think differently about `Arrays` :)
Doug Neiner
+1  A: 

implode(', ', $array_of_names)

pygorex1
+1  A: 

psuedocode....

integer sigh=container.getsize();
sigh--;
integer gosh=0;
foreach element in container
{
  if(gosh!=sigh)
    dosomething();
  else 
    doLastElementStuff();
  gosh++;
}

looking at all the other answers, it seems PHP has gotten a lot more syntactic S since I last wrote anything in it :D

Hassan Syed
I'd give you a +1 for reading the title, but I would have to give a -1 for not reading the question :)
Doug Neiner
The questions was edited while I wrote the answer :/
Hassan Syed
Ah, makes sense. I must have stumbled across it right after the edit.
Doug Neiner
+2  A: 

Sometimes you might not want to use implode. The trick then is to use an auxiliary variable to monitor not the last, but the first time through the loop. vis:

$names = array('Joe', 'Bob', 'Foobar');
$first = true;
$result = '';
foreach ($names as $name)
{
   if (!$first)
      $result .= ', ';
   else
      $first = false;

   $result .= $name;
}
dar7yl
A: 

I personally found the fastest way (if you're into micro optimization) is:

  if(isset($names[1])) {
     foreach ($names as $name) {
       $result .= $name . ', ';
    }
    $result = substr($result, 0, -2);
  } else {
    $result = $names[0];
  }

isset($names[1]) is the fastest (albeit not so clear) way of checking the length of an array (or string). In this case, checking for at least two elements is performed.

Raveren
You need `-2` instead of `-1` to remove the space __and__ the comma.
Doug Neiner
sorry, fixed, tired :]
Raveren
+1  A: 

I come accross this a lot building SQL statements etc.

$joiner = " ";
foreach ($things as $thing) {
    echo "  $joiner $thing \n";
    $joiner = ',';
}

FOr some reason its easier to work out the logic if you think of the ",", "AND" or "OR" as an option/attribute that goes before an item. The problem then becomes how to suppress the the "," on the first line.

James Anderson
Very cool as long as white space isn't an issue. But the concept is strong, and you could write it differently to remove the extra whitespace. +1
Doug Neiner
A: 

I actually find it easier to create my comma delimited text a little differently. It's a bit more wordy, but it's less function calls.

<?php
$nameText = "";
for ($i = 0; $i < count($nameArray); $i++) {
if ($i == 0) {
$nameText = $nameArray[$i];
}
else {
$nameText .= "," . $nameArray[$i];
}
}

It adds the comma as a prefix to every name except where it's the first element if the array. I have grown fond of using for as opposed to foreach since I have easy access to the current index and therefore adjacent elements of an array. You could use foreach like so:

<?php
$nameText = "";
$nameCounter = 0;
for ($nameArray as $thisName) {
if ($nameCounter == 0) {
$nameText = $thisName;
$nameCounter++;
}
else {
$nameText .= "," . $thisName;
}
}
Carlson Technology
But `count` evaluates again on each loop, so you still have one function call per loop. Additionally, you are introducing an `if` statement on every loop as well.
Doug Neiner