tags:

views:

101

answers:

8

I'm trying to 'pretty-print' out an array, using a syntax like:

$outString = "[";
foreach($arr as $key=>$value) {
    // Do stuff with the key + value, putting the result in $outString.
    $outString .= ", ";
}
$outString .= "]";

However the obvious downside of this method is that it will show a "," at the end of the array print out, before the closing "]". Is there a good way using the $key=>$value syntax to detect if you're on the last pair in the array, or should I switch to a loop using each() instead?

+4  A: 

You can just trim off the last ", " when for terminates by using substring.

$outString = "[";
foreach($arr as $key=>$value) {
  // Do stuff with the key + value, putting the result in $outString.
  $outString .= ", ";
 }

 $outString = substr($outString,-2)."]";  //trim off last ", "
Chris
+3  A: 

Do the processing separately and then use implode() to join:

$outArr = array();
foreach($arr as $key => $value) {
    $outArr[] = process($key, $value);
}
$outString = '[' . implode(', ', $outArr) . ']';
Edward Mazur
@Edward can you explain this answer? This is interesting.
Chris
@Chris - see my answer.
Dominic Rodger
@Chris I left out the extra processing, but you can use [implode()](http://php.net/manual/en/function.implode.php) to join array elements.
Edward Mazur
Thanks appreciate the comments.
Chris
+10  A: 

Build up an array, and then use implode:

$parts = array();
foreach($arr as $key=>$value) {
    $parts[] = process($key, $value);
}

$outString = "[". implode(", ", $parts) . "]";
Dominic Rodger
What does the `process()` function do?
Russell Dias
Whatever you want... Sorry, probably should have named it more helpfully - that's the bit for the OP to fill in.
Dominic Rodger
Don't worry, I got that. Thanks, this method works great. Will mark as answer when allowed to!
Stephen
Ah not a problem. Silly me.
Russell Dias
+2  A: 

It might be easier to do it like this, and add a comma to the string before the item if it isn't the first item.

$first= true;
foreach ($arr as $key => $value) {
    if (! $first) {
        $outString .=', ';
    } else {
      $first = false;
    }

    //add stuff to $outString
}

Is the output format JSON? If so you could consider using json_encode() instead.

Tom Haigh
@Tom although its not a big deal, to me this just adds complexity to the algorithm's efficiency when it does not need to be there.
Chris
Yes, but the approach is good too. It's easier to find if we're on the first element than the last. Useful algorithm which can be used.
Savageman
+1  A: 

You could do it as a normal for loop:

$outString = "[";
for ($i = 0; $i < count($arr); $i++) {
   // Do stuff
   if ($i != count($arr) - 1) {
      $outString += ", ";
   }
 }

However, the nicest way to do it, IMHO, is storing all the components in an array, and then imploding:

 $outString = '[' . implode(', ', $arr) . ']';

implode() takes all elements in an array and puts them together in a string, separated by its first argument.

eliego
+2  A: 

Notwithstanding the circumstances of your example (joining strings with commas, for which implode is the right way to go about it), to answer your specific question, the canonical way to iterate through an array and check if you're on the last element is using CachingIterator:

<?php
$array = array('k'=>'v', 'k1'=>'v1');

$iter = new CachingIterator(new ArrayIterator($array));
$out = '';
foreach ($iter as $key=>$value) {
    $out .= $value;

    // CachingIterator->hasNext() tells you if there is another
    // value after the current one.
    if ($iter->hasNext()) {
        $out .= ', ';
    }
}
echo $out;
Shabbyrobe
Wow - I've never seen incomplete docs on the PHP site before - "Description here..." everywhere!
Dominic Rodger
Yeah, some of the areas of the documentation haven't been fleshed out. I've been working with the DOMDocument stuff lately and it's similarly patchy. There's ancillary documentation for the SPL [here](http://www.php.net/~helly/php/ext/spl/), but it's not that much more helpful.
Shabbyrobe
+1  A: 

There are many possibilities. I think this is one of the simplest solutions:

$arr = array(0 => 'a', 1 => 'b', 2 => 'c', 3 => 'd', 4 => 'e', 5 => 'f', 6 => 'g');

echo '[', current($arr);
while ($n = next($arr)) echo ',', $n;
echo ']';

Outputs:

[a,b,c,d,e,f,g]
Richard Knop
A: 

I tend to avoid using loops in situations such as these. You should use implode() to join lists with a common deliminator and use array_map() to handle any processing on that array before the join. Note the following implementations that should express the versatility of these functions. Array map can take a string (name of a function) representing either a built-in function or user defined function (first 3 examples). You may pass it a function using create_function() or pass a lambda/anonymous function as the first parameter.

$a = array(1, 2, 3, 4, 5);

// Using the user defined function
function fn ($n) { return $n * $n; }
printf('[%s]', implode(', ', array_map('fn', $a)));
// Outputs: [1, 4, 9, 16, 25]

// Using built in htmlentities (passing additional parameter
printf('[%s]', implode(', ', array_map( 'intval' , $a)));
// Outputs: [1, 2, 3, 4, 5]

// Using built in htmlentities (passing additional parameter
$b = array('"php"', '"&<>');
printf('[%s]', implode(', ', array_map( 'htmlentities' , $b, array_fill(0 , count($b) , ENT_QUOTES) )));
// Outputs: [&quot;php&quot;, &quot;&amp;&lt;&gt;]

// Using create_function <PHP 5
printf('[%s]', implode(', ', array_map(create_function('$n', 'return $n + $n;'), $a)));
// Outputs: [2, 4, 6, 8, 10]

// Using a lambda function (PHP 5.3.0+)
printf('[%s]', implode(', ', array_map(function($n) { return $n; }, $a)));
// Outputs: [1, 2, 3, 4, 5]
Bryan Correll