2

私は clojure を使用する旅を始めましたが、自分で設定した最初の問題に困惑しました。基本的にnXm行/列のテーブルであるテキストファイルがあります。最初の行は列名で、最初の列は行名です。clojure を使用してこのテーブルを解析し、後で table[row][column] をクエリしてその値を取得できるようにしたいと考えています。

  a  b  c
1 7  8  9
2 s  q  r
3 2  7  1

では、上記のテーブルを clojure でどのように使用するのでしょうか? どこから始めればよいかよくわかりません。誰かが私を正しい方向に導くことができますか?

4

2 に答える 2

6

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

データが取り出されたので、あとはそれをつなぎ合わせるだけです。これを行う簡単な方法は、行から列、要素への個々のマッピングをすべて構築し、それらを結合することです。これは最も効率的な方法ではありませんが、かなりきれいです。

pairs2 つのコレクションの要素を単純に並べて貼り付けるヘルパー関数を作成すると、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"
于 2013-04-03T06:30:35.800 に答える
2

https://github.com/clojure/data.csvを使用すると、ファイルはベクトルのシーケンスになり、それぞれが行になり、次のような関数で行を解析できます。

(defn parse-row [[a b c]]
 [(Integer/parseInt a) (Double/parseDouble b) (str c)])

(引数リストの構造化に注意してください。これにより、列名が読みやすくなります)

次に(map parse-row rows)、解析されたテーブルを取得します

ただし、別の方法はIncanterを使用することです。これにより、csv ファイルがクエリしやすいマトリックスに変換されます。

于 2013-04-03T03:48:58.223 に答える