开发者

What are clever ways to output a list of n items with (n-1) separators inbetween?

Let's say that we have an array with n elements (n > 0).

We would like to output a list of those elements, with a separator between them.

A common approach to this problem is:

foreach item
  (
    output item
    output separator
  )
trim last separator

But it seems a bit messy to have to do that.

Another approach would be:

check that there is at least one element
loop
  (
     output element
     next element, or break if no more elements
     output separator
  )

But I am not sure that it will always work.

Do开发者_C百科 you see other clever ways to do that, for example in C, C++?


char *sep = "";
for (i = 0; i < size; ++i) {
    printf("%s%s", sep, item[i]);
    sep = ", ";
}


for (i = 0; i < n; ++i) switch(i) {
    default: output_separator();
    case 0: output_item(i);
}

or variations on this. I can't really think of how else not to repeat output_item(i).


Sometimes:

output item 0
for item 1 to n
{
    output separator
    output item
}

is shorter.


As it is tagged as language-agnostic I think it's important to point out, that some languages have built-in features to spare you from even thinking about this problem. Take this python code for example:

>>> print string.join(['list', 'of', 'some', 'words'], ', ')
list, of, some, words


A possible C++ solution:

http://groups.google.com/group/comp.lang.c++/msg/a746a588cedfa44b

Summary: write an infix_ostream_iterator, which is basically the same as ostream_iterator except that the "separator" parameter really is a separator, not a suffix to every item. Usage would then be:

std::copy(first, last, infix_ostream_iterator<ItemType>(output, separator));


For better or worse, I use counted loops, with

for (i = 0; i < num_items; i++){
  if (i > 0) output separator;
  output item[i];
}

I'm sure this is downvote-bait for being old fashioned, but it works.

If anybody wants to tell me it's inefficient, boy do I have a flame ready ;-)


This version avoids any additional branches:

int i = 0;
goto skip_delim;
do {
               put_delim();
   skip_delim: put_el(i++);
} while (i < size);

(For those who are afraid of goto, it can be written using approach from Duff's device)


The "first check" idiom in Haskell:

intersperse :: Show a => String -> [a] -> String
intersperse _ [] = ""
intersperse s (x:xs) = show x ++ concatMap ((s ++) . show) xs

It's used like so:

*Main> intersperse "," [1,2,3]
"1,2,3"
*Main> intersperse "," [1]
"1"
*Main> intersperse ";" [1,2]
"1;2"
*Main> intersperse "," []
""


I always use first item check idiom. Here is the code in java:

List<Object> list;
if (list.size() > 0) {
   put(list.get(0));
}
for(int i = 1; i < list.size(); i++) {
   putSeparator();
   put(list.get(i));                                
}


for i in items.length-1; do
   output item; output separator
output last item


In Common Lisp, it's bordering on simple, as long as you can hard-code the separator.

(defun return-delimited-list (list &optional stream)
  (format stream "~{~A~^, ~}" list))

When called, this returns a string consisting of the elements in list, separated by ", " (except for the last element not being followed by anything). Well, if fed an output stream, it prints it to the stream, it just so happens that 'nil' means "No stream, just return a string".

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜