CommonLispで多次元連想配列を実装するための最良の方法を探しています。私はSBCLを使用しています。
たとえば、MATLABでは、次のような構造体配列を作成できます。いくつかの地理データを使用:
my_array.Finland.capital = 'Helsinki';
my_array.Finland.northernmost_municipality = 'Utsjoki';
my_array.Norway.capital = 'Oslo';
そして、動的フィールド名を使用してそれを参照します。
country = 'Finland';
city_status = 'capital';
my_array.(country).(city_status)
'Helsinki'
結果として文字列が得られます。
では、Common Lispで多次元(n次元)連想配列を実装するための最良の方法は何でしょうか?(上記のMATLABの例のように)
aref
ハッシュテーブルを使用して値/キー(文字列として指定)を数値アドレスに変換し、それらの数値アドレスをインデックスとして多次元配列に渡すことに基づく実用的なソリューションを見つけました。しかし、私はそれを行うためのより良い方法があるのだろうか?文字列を他の文字列に、文字列をリストに、文字列を数値に変換する必要があります(以下の例のように)。
私の解決策はこれです(英語で書かれた数値を数値表現に変換するためのサンプルデータを使用):
以下の関数list-to-3d-array
は、CommonLispに対するRainerJoswigの答えの最小限に変更されたバージョンです:リストと配列の間で変換します。
;;; functions.
(defun list-to-3d-array (my-list)
(make-array (list (length my-list)
(length (first my-list))
(length (first (first my-list))))
:initial-contents my-list))
(defun prepare-hash-table (my-hash-table factor-name factor-values-list)
"This function stores values from 0 to n for the keys created by concatenating the factor-name and the values given in a list."
(loop for i from 0 to (1- (length factor-values-list))
do (setf (gethash (concatenate 'string factor-name "-" (nth i factor-values-list)) my-hash-table) i)))
(defun return-value-from-assoc-array (my-array my-hash-table hundreds tens ones)
(aref my-array
(gethash (concatenate 'string "hundreds-" hundreds) my-hash-table)
(gethash (concatenate 'string "tens-" tens) my-hash-table)
(gethash (concatenate 'string "ones-" ones) my-hash-table)))
;;; functions end here.
;;; some example data.
(defparameter *array-contents*
(list
(list
(list 111 112 113)
(list 121 122 123)
(list 131 132 133))
(list
(list 211 212 213)
(list 221 222 223)
(list 231 232 233))
(list
(list 311 312 313)
(list 321 322 323)
(list 331 332 333))))
(defparameter *hundreds-in-english* (list "hundred" "twohundred" "threehundred"))
(defparameter *tens-in-english* (list "ten" "twenty" "thirty"))
(defparameter *ones-in-english* (list "one" "two" "three"))
(defparameter *my-hash-table* (make-hash-table :test 'equal))
;;; example parameters end here.
;;; prepare the array.
(defparameter *my-array* (list-to-3d-array *array-contents*))
;;;; prepare the hash table.
(prepare-hash-table *my-hash-table* "hundreds" *hundreds-in-english*)
(prepare-hash-table *my-hash-table* "tens" *tens-in-english*)
(prepare-hash-table *my-hash-table* "ones" *ones-in-english*)
次に、例えば。(return-value-from-assoc-array *my-array* *my-hash-table* "hundred" "ten" "two")
出力:
112