我正在寻找在 Common Lisp 中实现多维关联数组的最佳方法。我正在使用 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
是 Rainer Joswig 对Common Lisp 的回答的最小修改版本:在列表和数组之间转换。
;;; 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