@Hendekagonの答えは仕事を成し遂げるための良い方法ですが、ゼロからの実装を見ることができます. おそらく最善の解決策ではありませんが、サンプル デザインが作業を開始するのに役立つことを願っています。
Clojure で構造を照会する場合は、マップについて考える必要があります。次のようなものを目標としてみましょう。
{"1" {"a" "7", "b" "8", "c" "9"},
"2" {"a" "s", "b" "q", "c" "r"},
"3" {"a" "2", "b" "7", "c" "1"}}
ここで、行名は、列名をテーブル要素にマップするためのキーです。この構造により、 を使用してテーブルの要素を簡単にクエリできますget-in
。
(get-in table ["2" "b"]) ; => "q"
わかった。どうやってそれをするのですか?
ファイルを既に読み込んで、それを文字列として持っているふりをしましょう。次に、それを map-of-maps に変換する必要があります。関数は次のようになります。
(defn parse-table
[raw-table-data]
...)
最初のステップは、データの重要な部分 (行名、列名、テーブル要素) をすべて抽出することです。ただし、それらを取得する前に、raw-table-data
文字列をより簡単にトラバースできる構造に解析する必要があります。文字列を改行で分割し、ヘルパー関数を使用して空白で行をトークン化しますtokens
。
(use '[clojure.string :only [split split-lines trim]])
(defn tokens
[s]
(-> s trim (split #"\s+")))
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))]
...
)
table-data
次のようになります。
[["a", "b", "c"],
["1", "7", "8", "9"],
["2", "s", "q", "r"],
["3", "2", "7", "1"]]
これにより、良いものに簡単にアクセスできます。
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))
column-names (first table-data)
row-names (map first (next table-data))
contents (map next (next table-data))]
...
)
データが取り出されたので、あとはそれをつなぎ合わせるだけです。これを行う簡単な方法は、行から列、要素への個々のマッピングをすべて構築し、それらを結合することです。これは最も効率的な方法ではありませんが、かなりきれいです。
pairs
2 つのコレクションの要素を単純に並べて貼り付けるヘルパー関数を作成すると、for
内包表記を使用して一連のマッピングを取得できます。
(defn pairs
[coll1 coll2]
(map vector coll1 coll2))
(for [[row-name row-contents] (pairs row-names contents)
[column-name element] (pairs column-names row-contents)]
{row-name {column-name element}})
これにより、マップからマップへのシーケンスが得られます。それを 1 つの大きなマップにマージするだけで、機能は完了です。
(defn parse-table
[raw-table-data]
(let [table-data (map tokens (split-lines raw-table-data))
column-names (first table-data)
row-names (map first (next table-data))
contents (map next (next table-data))]
(apply merge-with merge
(for [[row-name row-contents] (pairs row-names contents)
[column-name element] (pairs column-names row-contents)]
{row-name {column-name element}}))))
これで、テーブル ファイルを丸呑みして解析できます。
(def table
(->
"file"
slurp
parse-table))
これで目標に到達できます。
(println (get-in table ["2" "b"])) ; => "q"