CSV ファイルをテーブル表示する(解説編)

 前回の “newLISP で GUI する。。。または、CSV ファイルをテーブル表示する。” は、如何だったでしょうか?
 今回の解説は、中で使っている、リストから テーブル表示用の HTML文字列を作る関数makeHTMLtable についてです。

(define *header* [text]<!-- generated page -->
<html>
<table border="1">
[/text])
(define tableROW '("<tr>" "</tr>\n"))
(define tableDATA '("<td align=\"right\">" "</td>"))
(define tableHEADER '("<th>" "</th>"))
(define *footer* [text]</table>
</html>
[/text])
(defun addHTMLtag (data tag)
  (string (tag 0) data (tag 1)))
(defun makeHTMLtable1 (lst)
  (let (html *header*)
    (dolist (row lst)
      (extend html (tableROW 0))
      (dolist (col row) 
        (extend html (addHTMLtag col (if (string? col) tableHEADER tableDATA))))
      (extend html (tableROW 1)))
    (extend html *footer*)))

 やっていることは、

  1. 入れ子リストの引数を要素にまで分解
  2. その要素に補助関数addHTMLtag でタグを付加
  3. それを extend でつなぎ合わせていく

 上記コードは、いかにも手続きですが、動作を見るには、これが一番わかりやすいので(汗)。でも、関数プログラミング言語の newLISP なら、map を使って、関数表記(?)できるはず。
 と、言うことで、mapappend の合成関数 mappend(Common Lisp にある mapcan の append 版)を使って、dolist を無くてみましょう。
 手始めに、

(defun makeHTMLtable2 (lst)
  (let (html *header*)
    (dolist (row lst)
      (extend html (addHTMLtag (mappend (fn (col) (addHTMLtag col (if (string? col) tableHEADER tableDATA))) row)
                               tableROW)))
    (extend html *footer*)))

 これで、一番下の dolist が消えました(笑)。
 動作は、

> mappend
(lambda () (apply append (apply map (args))))
> (setq csv (makeHTMLtable1 sol-sys))
[text]<!-- generated page -->
<html>
<table border="1">
<tr><th>Planet name</th><th>Equator diameter (earth)</th><th>Mass (earth)</th><th>Orbital radius (AU)</th><th>Orbital period (years)</th><th>Orbital Incline Angle</th><th>Orbital Eccentricity</th><th>Rotation (days)</th><th>Moons</th></tr>
<tr><th>Mercury</th><td align="right">0.382</td><td align="right">0.06</td><td align="right">0.387</td><td align="right">0.241</td><td align="right">7</td><td align="right">0.206</td><td align="right">58.6</td><td align="right">0</td></tr>
<tr><th>Venus</th><td align="right">0.949</td><td align="right">0.82</td><td align="right">0.72</td><td align="right">0.615</td><td align="right">3.39</td><td align="right">0.0068</td><td align="right">-243</td><td align="right">0</td></tr>
<tr><th>Earth</th><td align="right">1</td><td align="right">1</td><td align="right">1</td><td align="right">1</td><td align="right">0</td><td align="right">0.0167</td><td align="right">1</td><td align="right">1</td></tr>
<tr><th>Mars</th><td align="right">0.53</td><td align="right">0.11</td><td align="right">1.52</td><td align="right">1.88</td><td align="right">1.85</td><td align="right">0.0934</td><td align="right">1.03</td><td align="right">2</td></tr>
<tr><th>Jupiter</th><td align="right">11.2</td><td align="right">318</td><td align="right">5.2</td><td align="right">11.86</td><td align="right">1.31</td><td align="right">0.0484</td><td align="right">0.414</td><td align="right">63</td></tr>
<tr><th>Saturn</th><td align="right">9.41</td><td align="right">95</td><td align="right">9.54</td><td align="right">29.46</td><td align="right">2.48</td><td align="right">0.0542</td><td align="right">0.426</td><td align="right">49</td></tr>
<tr><th>Uranus</th><td align="right">3.98</td><td align="right">14.6</td><td align="right">19.22</td><td align="right">84.01</td><td align="right">0.77</td><td align="right">0.0472</td><td align="right">-0.718</td><td align="right">27</td></tr>
<tr><th>Neptune</th><td align="right">3.81</td><td align="right">17.2</td><td align="right">30.06</td><td align="right">164.8</td><td align="right">1.77</td><td align="right">0.0086</td><td align="right">0.671</td><td align="right">13</td></tr>
<tr><th>Pluto</th><td align="right">0.18</td><td align="right">0.002</td><td align="right">39.5</td><td align="right">248.5</td><td align="right">17.1</td><td align="right">0.249</td><td align="right">-6.5</td><td align="right">3</td></tr></table>
</html>
[/text]
> (= csv (make-table2 sol-sys))
true
> 

 さらに、もう一段 dolist を関数化すると、

(defun makeHTMLtable3 (lst)
  (addHTMLtag
    (mappend (fn (row) (addHTMLtag (mappend (fn (col) (addHTMLtag col (if (string? col) tableHEADER tableDATA)))
                                            row)
                                   tableROW))
             lst)
    (list *header* *footer*)))

 こんな感じ。ここなら、補助関数addHTMLtag を作った甲斐があるというもの(笑)。
 動作は、もちろん、

> (= csv (make-table3 sol-sys))
true
> 

 同じです。

 まとめとしては、

リストの要素に対する操作が同一のリスト操作で、

  • 戻り値がリストになるなら map
  • append したリストや文字列になるなら mappend

が使える。
また、要素ごとに処理が複雑に異なるなら、dolist を使う。

 こんなところ、、、当たり前か?(笑)

 以上、如何でしょうか?

No comments yet

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。