2016-12-04 7 views
1

Common Lispでは、すべてのlispオブジェクトをハッシュテーブルキーとして扱うことができます。しかし、オブジェクトの一部だけをキーとして使用したい場合はどうでしょうか。たとえば、構築されたキーを使った効率的なハッシュテーブルアクセス

(defstruct action 
    (name nil :type symbol) 
    (parameters nil :type list) 
    (time 0 :type fixnum) 
    (database nil :type hash-table)) 

の場合、タイムスロットはequalpハッシュ状況には不適切です。キーとして(部分的な)lispオブジェクトを使用してハッシュテーブルにアクセスするための良い戦略は何ですか? 1つの手法では(list (action-name act1) (action-parameters act1) (action-database act1))のようなキーを使用することがありますが、これはむしろ非効率的です。別のアプローチでは、3つの適切なスロットだけを使ってアクション構造体にサブストラクチャを作成し、そのサブストラクチャをキーとして使用することもできますが、これはハッシュテーブルアクセスの目的のために多少アドホックに見えます。よりうまくいく他の方法がありますか?

+1

参照:http://stackoverflow.com/q/33828408/124319を。非効率的では、適切なタイミングなしにそれを言うことはできません。これはすぐにガベージコレクションされる非常に小さな割り当てのようです。 – coredump

+0

'(データベースnil:型ハッシュテーブル)'は '(データベース(make-hash-table):型ハッシュテーブル)'でなければならないと思います。それ以外の場合は、 'action'が作成されるとエラーがスローされます。 – tsikov

+0

@coredump:そうです。クイックテストでは、キーの構造とスロットのリストの構造を使用してもタイミングの差はごくわずかです。また、私のアプリケーションには適用されませんが、あなたの参照のインターンシップのアプローチは、特定の状況で有用である可能性があります。別の考え方は、ハッシュ・テーブル・アクセスのためだけに不適切なスロットを一時的にヌル値に設定し、構造全体をキーとして保持することです。 – davypough

答えて

0

私はあなたがこのようなアクションを作成するときに最初に、あなたのコードに行くたとえばとして、hereから

cl-custom-hash-table

をCommon Lispのライブラリを使用します。

CL-USER> (setq action-1 (make-action 
    :parameters '(1 2 3) 
    :time 45)) 

は、このエラーが発生します:

The value NIL is not of the expected type HASH-TABLE. 
    [Condition of type TYPE-ERROR] 

CL-USER> (defstruct action 
    (name nil :type symbol) 
    (parameters nil :type list) 
    (time 0 :type fixnum) 
    (database (make-hash-table) :type hash-table)) 
ACTION 
CL-USER> (setq action-1 (make-action 
    :parameters '(1 2 3) 
    :time 45)) 

#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 45 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012E708D>) 

は、その後、あなたが同じ時間か、これまで何を次のように必要とする関数を定義する必要があります:このような何かにあなたの定義をハンゲデータにaccesing

CL-USER> (action-time action-1) 
45 

別のアクションを作成

CL-USER> (setq action-2 (make-action 
    :parameters '(1 2 3) 
    :time 102)) 

#S(ACTION :NAME NIL :PARAMETERS (1 2 3) :TIME 102 :DATABASE #<HASH-TABLE :TEST EQL size 0/60 #x3020012FE58D>) 

テスト用の関数を作成する

CL-USER> (defun equal-actions-by-time (a1 a2) (= (action-time a1) (action-time a2))) 
EQUAL-ACTIONS-BY-TIME 

ハッシュ関数を定義します。

CL-USER> (defun hash-action (a) (action-time a)) 
HASH-ACTION 

は、あなたのハッシュ

CL-USER> (define-custom-hash-table-constructor make-action-hash :test equal-actions-by-time :hash-function hash-action) 
MAKE-ACTION-HASH 
CL-USER> (defparameter *foo-hash* (make-action-hash) "variable for stackoverflow") 
*FOO-HASH* 

を作成し、それを試してみてください。

CL-USER> (setf (gethash action-1 *foo-hash*) 1 
      (gethash action-2 *foo-hash*) 10) 
10 

CL-USER> (gethash action-1 *foo-hash*) 
1 
T 

分布が実装で動作する場合は、ライブラリの使用を避けることができますカスタムTEST/HASH関数をネイティブにサポートしています。カスタムハッシュテーブルで使用できない場合は

あなたは次のように動作することができますオプティマス場合

CL-USER> (defparameter *foo-hash* (make-hash-table :test 'equal-actions-by-time :hash-function 'hash-action)) 
*FOO-HASH* 
CL-USER> (setf (gethash action-1 *foo-hash*) 1 
      (gethash action-2 *foo-hash*) 10) 
10 
CL-USER> (gethash action-1 *foo-hash*) 
1 
T 
+0

あなたの洞察力の再カスタムハッシュテーブルをありがとう。しかし私は、私の元の問題に対するカスタムvs標準の利点についてまだ明確ではない。その3スロットの有効キーについては、カスタムハッシュテーブルテスト関数で(と(eq(アクション名a1)(アクション名a2))(等価(アクションパラメータa1)(アクションパラメータa2) (action-database a1)(action-database a1))を使用するのに対し、標準のequalpハッシュテーブルは単純に(list(action-name a1)キー。この場合、カスタムテーブルは標準テーブルよりも大幅に効率的ですか? – davypough

+0

ハッシュテーブルを使用する方がリストより効率的です。こちらをご覧くださいhttps://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node154.html – anquegi

+0

@davypough手動で変換することができますmsgstr "" "アクションインスタンスをリストに入れてからハッシュテーブルのキーとして使用します。カスタムハッシュテーブルを使用する利点は読みやすいことです。この変換はすべてのハッシュテーブル呼び出しに対して言及する必要はなく、ハッシュテーブルを定義するときに1回だけ必要です。パフォーマンス上の利点は、これらの一時的なリストを避けることです。 – zut

関連する問題