What are clever ways to output a list of n items w

2020-02-26 10:52发布

问题:

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 you see other clever ways to do that, for example in C, C++?

回答1:

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


回答2:

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).



回答3:

Sometimes:

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

is shorter.



回答4:

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


回答5:

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));


回答6:

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 ;-)



回答7:

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)



回答8:

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 "," []
""


回答9:

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));                                
}


回答10:

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


回答11:

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".