Programming Puzzle: What is the best way to format a comma delimited list?

Say you have a list, array, vector, storage format doesn't matter:

std::vector<int> vec;
vec.push_back(1);
vec.push_back(17);
vec.push_back(9);

And you want to format this list into a comma delimited string without the trailing comma, what is the best way to do this?

Example output:

1,17,9

In any language, with any list type. Post your answers here. Be sure to use code formatting for your answer, to make it easier for everyone to read.

<code language="lua">
--my code solution
</code>

Comments

Absolutely trivial in

Absolutely trivial in Perl:

$output = join( ',', @list );

I figured there would be at

I figured there would be at least one language where this was the case. Make me wonder how exactly "join" is implemented tho.

Haskell

There might be slicker ways to do it, but here's a Haskell way:

From GHCi:

> import Data.List
> let a = [1, 2, 3]
> intercalate ", " (map show a)

Haskell, again

I'm definitely not a haskell coder, by any stretch, but here's a stab at function by cases:

recomma []     = ""
recomma [a]    = show a
recomma (a:as) = show a ++ ", " ++ recomma as
 
main = putStrLn (recomma [1, 2, 3])

Very similar to any example from Simon Peyton Jones' "Taste of Haskell" talk: http://research.microsoft.com/en-us/um/people/simonpj/papers/haskell-tut...

Python

Similar idea in Python:

a = ', '.join(map(str, vals))

Ruby

Simple like perl

s = a.join(', ')

Minnow

A great example of why Minnow needs generics or dynamic types. That function should be parametric or be part of array:

def recomma(a : Array[int]) : string
  if (a.size() == 0)
    return ""
  else
    $ret_val = a[0].to_string()
    for $i = 1 to a.size()-1
      ret_val += ", " + a[i].to_string()
    end
  end
  return ret_val
end
 
action main
  print(recomma([1, 2, 3]))
  Sys.exit()
end

I tried several different

I tried several different versions, including a templated function over the delimiter type. I settled for this since unnecessary templating is to be frowned upon (and it ran slightly slower).

This can easily be generalized to any sort of iterator, of course.

I made two versions. The second one runs slightly faster by my compiler but is "evil".

void printDelimitedList(const std::vector<int>::const_iterator& begin, const std::vector<int>::const_iterator& end, const char delim)
{
 
	if (begin!=end) //ignore empty lists
	{
		std::vector<int>::const_iterator cur=begin;
		std::cout << *begin; 
		while( ++cur!= end)
		{
			std::cout << delim <<*cur ;
		}
	}
 
}
 
void printDelimitedList2(const std::vector<int>::const_iterator& begin, const std::vector<int>::const_iterator& end, const char del)
{
 
	if (begin!=end)
	{
 
		std::vector<int>::const_iterator cur=begin;
loop:
		std::cout << *cur;
		if (++cur!= end)
		{
			std::cout << del;
			goto loop;
		}
	}
 
}

Here's a simpler one that's

Here's a simpler one that's more in CPP style.

void printwcomma(int val)
{	std::cout << ',' << val;  }
 
void printDelimitedList3(std::vector<int>::const_iterator& begin, const std::vector<int>::const_iterator& end)
{
	if (begin==end) return;
 
	std::cout<<*begin;
	std::for_each(++begin, end, printwcomma);
 
}

Javascript, PHP, Groovy, Falcon, Boo, C#, Vala

Javascript, PHP, Groovy, Falcon and Boo are about as terse as Perl / Ruby / Python on this one:

Javascript:

	[1,17,9].join(",");

PHP:

	implode(array(1,17,9), ",");

Groovy:

	[1,17,9].join(",");

Boo:

	[1,17,9].Join(",")

Falcon:

	strMerge(map(toString, [ 1, 17, 9 ]), ",")

C# is more verbose:

	public static string Intersperse<T> (T[] array, string delimiter)
	{
		Converter<T, string> cv = delegate(T i) { return i.ToString (); };
		string[] result = Array.ConvertAll<T, string>(array, cv);
		return String.Join(",", result);
	}

And Vala:

	public static string Intersperse (int[] array, string delimiter)
	{
		StringBuilder sb = new StringBuilder ();
		foreach (int i in array)
		{
			sb.append (i.to_string ());
			sb.append (delimiter);
		}
		sb.truncate (sb.len - delimiter.length);
		return sb.str;
	}

Oops. Typo on the C#, "return

Oops. Typo on the C#, "return String.Join(",", result);" should have been "return String.Join(delimiter, result);". It will also except if you pass anything that can't be converted to a string (like an object[] with some nulls). In production I'd use something closer to the Vala code, a la:

	public static string Intersperse<T> (IEnumerable<T> array, string delimiter)
	{
		string result;
		StringBuilder sb = new StringBuilder ();
		foreach (T i in array)
		{
			if (i == null)
				continue;
			sb.Append (i);
			sb.Append (delimiter);
		}
		result = sb.ToString ();
		return result.Substring (0, result.Length - delimiter.Length);
	}

Better C# version

Rather than using an extra string object and the Substring method, this is better (also uses the fact that StringBuilder methods are composable):

	public static string Intersperse<T> (IEnumerable<T> enumerable, string delimiter)
	{
		StringBuilder sb = new StringBuilder ();
		foreach (T item in enumerable)
		{
			if (item == null) continue;
			sb.Append (item).Append (delimiter);
		}
		sb.Length = sb.Length - delimiter.Length;
		return sb.ToString();
	}

in C# the solution is much

in C# the solution is much simpler

{1, 17, 9}.Select(i=>i.toString()).Aggregate("", (x, y) => x + "," + y)

Kind of...but not really.

Eh...kind of. But the way you're using the Aggregate method, you'll end up with ",1,17,9". You want to use the form with an initializer (first list item) and (next) list item (ps. you had a typo capitalizing the ToString method as well):

	{1, 17, 9}.Select(i=>i.ToString()).Aggregate((str, item) => str += "," + item)

Note that this will throw exceptions if you pass it arrays of nullable objects with actual nulls (or any other objects without a ToString method). Also, LINQ is nice and terse, but it doesn't always help readability.

Java

And a Java version (basically the same as Vala / C#):

	public static String Intersperse (Collection<?> collection, String delimiter)
	{
		StringBuilder sb = new StringBuilder ();
		for (Object item : collection)
		{
			if (item == null)
				continue;
			sb.append (item);
			sb.append (delimiter);
		}
		sb.setLength (sb.length () - delimiter.length ());
		return sb.toString ();
	}

NB. In the Vala, C#, Java versions, I'm appending the delimiter unconditionally, then truncating the final string to (length - delimiter length). This assumes that moving the end of string pointer once at the end (or updating the internal length variable, or whatever the implementation details may be) is less costly than checking some condition(s) once per loop to decide when to insert the delimiter.

Note also, that with Java,

Note also, that with Java, you can use StringUtils from Apache commons to get a join method that works similar to Perl, &c.

	StringUtils.join (new Object[]{1, 17, 9}, ",");

Clojure

(def mylist [1 17 9])
(apply str (interpose \, mylist))

of course

You can do it in-place as well:

(apply str (interpose ", " [1 17 9]))

Scala

From the REPL you can do:

println(Array(1, 17, 9).deepMkString(", "))

Scheme

And, just to be really esoteric, in Scheme we could do something like:

(string-join (map number->string '(1 17 9)) ",")

Oops, forgot a require...

Ps. Need to "(require scheme/string)" first for that example to work.

Ocaml version

Here's an Ocaml version (might be a better way, I was just bored and hadn't tinkered with ML for a spell):

String.concat "," (List.map string_of_int [1;17;9]);;