如何印清單

2005 年我問過 Thinker 這樣的問題:想程式常碰到要印出清單的情況,對人類而言習慣的格式是:

1, 2, 3, 4

但這個格式對於 C 語言來說卻不太好處理。一般可以寫成這樣:

<<一般作法>>=
void normal(const char *list[], const int len)
{
    int i = 0;
    printf("%s", list[i++]);
    for (; i < len; i++) {
        printf(", %s", list[i]);
    }
    puts("");
}
@

但是 printf 這行會重複,似乎不是最好的寫法。如果不要重複,那就得在迴圈中加個判斷式,但每次都要多個判斷又好像有點浪費:

<<判斷作法>>=
void condition(const char *list[], const int len)
{
    int i;
    for (i = 0; i < len; i++) {
        if (i != 0)
            printf(", ");
        printf("%s", list[i]);
    }
    puts("");
}
@

當時 Thinker 想了想,給了我一個用 function pointer 的答案

void dummy() {
}

void line() {
   printf("  ------\n");
}

inter = &dummy;
for(i = 0; i < n; i++) {
   inter();
   printf("%s\n", record[i]);
   inter = &line;
}

話說,事隔多年,今天在看其他東西的時候,突然想到這個問題可以用 Clifford’s Device 的方法做。

<<Clifford>>=
void clifford(const char *list[], const int len)
{
    int i = 0;
    while (1) {
        if (0) {
          clifford:
            printf(", ");
        }
        printf("%s", list[i++]);
        if (i >= len)
            break;
        goto clifford;
    }
    puts("");
}
@

各位看官,可有什麼新想法嗎?

<<list.c>>=
#include <stdio.h>

<<一般作法>>

<<判斷作法>>

<<Clifford>>

int main(int argc, char *argv[])
{
    const char *list[] = {
        "one",
        "two",
        "three",
    };
    const int l = sizeof(list) / sizeof(char *);

    normal(list, l);
    condition(list, l);
    clifford(list, l);
    return 0;
}
@

當然啦,如果是 python,這問題可簡單了:

>>> l = ['one', 'two', 'three']
>>> print ', '.join(l)
one, two, three

另,本文採用 Noweb 格式,用工具跑一遍就可以產生 list.c 。

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s