4

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
4

2 に答える 2

6

上記の設計と実装に同意しませんget-nested-hash(get-nested-hash 1)1を返さ(get-nested-hash 1 2)ないでください。また、nilを返さないでください。2つの引数を渡さないのはエラーです。のような意図的なnilを区別するには、複数の値を返す必要がありますgethashloop面倒で面倒です。check-typeデータが失われる可能性があるため、を介して修正可能なエラーを発行しないでください。

改善された解決策は次のとおりです。

(defun rec-hash (rec-hash key &rest more-keys)
  (if more-keys
      (apply #'rec-hash (gethash key rec-hash) more-keys)
      (gethash key rec-hash)))

(defun auto-vivify (rec-hash key)
  (multiple-value-bind (child exist) (gethash key rec-hash)
    (if exist
        child
        (setf (gethash key rec-hash)
              (make-hash-table :test (hash-table-test rec-hash))))))

(defun (setf rec-hash) (value rec-hash key &rest more-keys)
  (if more-keys
      (apply #'(setf rec-hash) value (auto-vivify rec-hash key) more-keys)
      (setf (gethash key rec-hash) value)))
于 2012-12-01T20:35:50.140 に答える
2

LispでProlog実装を使用することもできます。Prologは関係と事実を主張する可能性を提供し、論理規則を使用することができます。

LispWorksの簡単な関係は次のとおりです。

==> (defrel capital ((capital finland helsinki)))
YES.
OK.

==> (capital finland ?city)

?CITY = HELSINKI
OK.

==> (and (= ?country finland) (capital ?country ?city))

?COUNTRY = FINLAND
?CITY = HELSINKI
OK.

通常、LispのそのようなPrologは、Lispと埋め込まれたPrologの間のアクセスも提供します。

于 2012-11-29T20:25:01.027 に答える