Каковы умные способы вывести список из n элементов с (n-1) разделителями между ними? - PullRequest
7 голосов
/ 24 ноября 2010

Допустим, у нас есть массив с n элементами (n> 0).

Мы хотели бы вывести список этих элементов с разделителем между ними.

Общий подход к этой проблеме:

foreach item
  (
    output item
    output separator
  )
trim last separator

Но кажется, что это немного грязно.

Другой подход будет:

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

Но я не уверен, что это всегда будет работать.

Видите ли вы другие умные способы сделать это, например, в C, C ++?

Ответы [ 11 ]

16 голосов
/ 24 ноября 2010
char *sep = "";
for (i = 0; i < size; ++i) {
    printf("%s%s", sep, item[i]);
    sep = ", ";
}
11 голосов
/ 24 ноября 2010
for (i = 0; i < n; ++i) switch(i) {
    default: output_separator();
    case 0: output_item(i);
}

или вариации на это.Я не могу придумать, как еще не повторить output_item(i).

5 голосов
/ 24 ноября 2010

Что бы там ни было, я использую счетные циклы с

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

Я уверен, что это приманка для старомодных, но это работает.чтобы сказать мне, что это неэффективно, мальчик, у меня есть готовый огонь; -)

5 голосов
/ 24 ноября 2010

Возможное решение C ++:

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

Сводка: напишите infix_ostream_iterator, что в основном совпадает с ostream_iterator, за исключением того, что параметр "separator" действительно является разделителем, а не суффиксом для каждого элемента. Использование тогда будет:

std::copy(first, last, infix_ostream_iterator<ItemType>(output, separator));
5 голосов
/ 24 ноября 2010

Поскольку он помечен как независимый от языка, я думаю, что важно отметить, что некоторые языки имеют встроенные функции, позволяющие вам даже не задумываться над этой проблемой.Возьмите этот код Python, например:

>>> print string.join(['list', 'of', 'some', 'words'], ', ')
list, of, some, words
5 голосов
/ 24 ноября 2010

Иногда:

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

короче.

3 голосов
/ 25 ноября 2010

Идиома «первой проверки» в Haskell:

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

Используется так:

*Main> intersperse "," [1,2,3]
"1,2,3"
*Main> intersperse "," [1]
"1"
*Main> intersperse ";" [1,2]
"1;2"
*Main> intersperse "," []
""
3 голосов
/ 24 ноября 2010

Эта версия избегает любых дополнительных веток:

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

(Для тех, кто боится goto, его можно записать, используя подход с устройства Даффа) * ​​1005 *

2 голосов
/ 24 ноября 2010

Я всегда использую идиому проверки первого элемента. Вот код в 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));                                
}
1 голос
/ 24 ноября 2010

В Common Lisp он граничит с простым, если вы можете жестко закодировать разделитель.

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

При вызове возвращает строку, состоящую из элементов в list, разделенных "," (за исключением того, что за последним элементом ничего не следует). Что ж, если передать выходной поток, он печатает его в поток, просто так получается, что 'nil' означает «Нет потока, просто верните строку».

...