0

宿題の2つのリストを比較する関数を書こうとしています。関数を実行すると、次のようになります;(cmp'(cat?x mat?x)'(cat bat mat bat))=> t;(cmp'(cat?x mat?x)'(cat bat mat sat))=>nil。つまり、最初のリストで?xに等しい場合、2番目の?xは、両方が同じ値を指している場合にtrueを返します。プログラムを実行すると、「次の場合に引数を特殊形式に解析中にエラーが発生します:要素の数が無効です」フィードバックをいただければ、次のコードが表示されます。ありがとう。

;cmp algorithm
;1 if the both lists are empty return true
;2 if only one of the lists is empty return fasle
;3 compare first of the list1 and the first of list2
;if equal go on to the rest of the list with recursive call else return false   

(defun cmp (list1 list2)
(setq y '())
(setq z '())
(defparameter *counter* 0)
  (cond 
   ((and (null list1) (null list2))
    t 
    )
   ((or (null list1) (null list2))
    nil
    )
    ((or (eq (first list1) (first list2)) 
         (eq (first list1) '?x)  )
     (cmp (rest list1) (rest list2) )

        ;if (first list is equal to '?x)
        ;set the counter to 1
        ;give the value of (first(rest list2)) to y 
        ;if (first list is equal to '?x) again
        ;set the counter to 2
        ;give the value of (first (rest list2)) to z
        ;i need to compare y and z if eq return true

     (if (eq (first list1) '?x) 
        (princ (first list1 ))
        (princ (first(rest list2)))

        (1+ *counter*)
        (set y (first(rest list2)))

        (if (= *counter* 2)
        (set z (first (rest list2)))    
            )       
        )

        (if (= y z) t)      
     )
   (t
    nil)
   )
  )





;(cmp ‘(cat ?x mat ?x) ‘(cat bat mat bat))  =>  t 
  ;(cmp ‘(cat ?x mat ?x) ‘(cat bat mat sat))  =>  nil
4

2 に答える 2

2

本やドキュメントを読むことは確かに役立ちますが、特に問題をすでに理解した後で、サンプルコードを見ると役立つこともあります。気取らない簡単な解決策は次のとおりです。

(defun compare-using-wildcards (pattern matched)
  (loop for p in pattern
     for m in matched
     with keys = (make-hash-table)
     do (unless (eql p m)               ; Doesn't matter
                                        ; if it starts with ?
                                        ; we still don't consider
                                        ; it a wildcart symbol, if
                                        ; it matches the symbol in
                                        ; the other list.
          (if (and (symbolp p)
                   (char= (aref (symbol-name p) 0) #\?))
              (multiple-value-bind (registered exists)
                  (gethash p keys)
                (if exists
                    (unless (eql registered m)
                      (return))
                    (setf (gethash p keys) m)))
              (return)))
     finally (return t)))

(compare-using-wildcards '(cat ?x mat ?x) '(cat bat mat bat)) ; T
(compare-using-wildcards '(cat ?x mat ?x) '(cat bat mat sat)) ; NIL
(compare-using-wildcards '(cat ?x mat ?y) '(cat bat mat sat)) ; T
(compare-using-wildcards '(cat ?x max ?y) '(cat bat mat sat)) ; NIL

しかし、これを行うにはたくさんの方法があります!たとえば、リストが短いことがわかっている場合は、を介してこれを実行できますdestructuring-bind。または、「zip」関数(nil以外の結果が返されるまで、複数のリストから他の関数​​にセルをフィードする高階関数)などを作成することもできます。


そして、やや不自然な例。まあ、私がいくつかのコーナーケースを逃していない限り、それはうまくいくはずのようです。複数のリストをワイルドカード付きのリストと比較します。

(every (let ((keys (make-hash-table)))
       #'(lambda (&rest elements)
           (let ((wildcard (car elements)))
             (if (and (symbolp wildcard)
                      (char= (aref (symbol-name wildcard) 0) #\?))
                 (let ((replacement (gethash wildcard keys))
                       (i -1))
                   (if replacement
                       (every #'(lambda (x)
                                  (eql x (aref replacement (incf i))))
                              (cdr elements))
                       (setf (gethash wildcard keys)
                             (coerce (cdr elements) 'vector))))
                 (every #'(lambda (x) (eql x wildcard)) elements)))))
     '(cat ?x mat ?x)
     '(cat bat mat bat)
     '(cat bar mat bar)
     '(cat bank mat bank)
     '(cat bass mat boss))
于 2012-11-16T23:45:05.363 に答える
1

もうすぐです。?最初の文字がであるシンボルを一般的に照合する方法と、再帰呼び出しに照合を渡す方法がありません。

呼び出しの間のどこかに一致を保存する必要があります。考えられるアプローチは、一致のオプションの関連付けリストでそれらを渡すことです。

(defun cmp (list1 list2 &optional matches)
  (cond ((and (null list1) (null list2))
         t)
        ((or (null list1) (null list2))
         nil)
        ((and (symbolp (first list1))
              (plusp (length (symbol-name (first list1))))
              (eql (char (symbol-name (first list1)) 0) #\?))
         (let ((assoc (assoc (first list1) matches)))
           (cond ((null assoc)
                  (cmp (rest list1) (rest list2)
                       (list* (cons (first list1) (first list2))
                              matches)))
                 ((eql (cdr assoc) (first list2))
                  (cmp (rest list1) (rest list2) matches)))))
        ((eql (first list1) (first list2))
         (cmp (rest list1) (rest list2) matches))))

動的変数を使用するこれと非常によく似たアプローチ:

(defvar *matches* '())

(defun cmp (list1 list2)
  (cond ((and (null list1) (null list2))
         t)
        ((or (null list1) (null list2))
         nil)
        ((and (symbolp (first list1))
              (plusp (length (symbol-name (first list1))))
              (eql (char (symbol-name (first list1)) 0) #\?))
         (let ((assoc (assoc (first list1) matches)))
           (cond ((null assoc)
                  (let ((*matches* (list* (cons (first list1) (first list2))
                                          *matches*)))
                    (cmp (rest list1) (rest list2))))
                 ((eql (cdr assoc) (first list2))
                  (cmp (rest list1) (rest list2))))))
        ((eql (first list1) (first list2))
         (cmp (rest list1) (rest list2)))))

どちらも次のように呼び出すことができます。

> (cmp '(?x b ?x d ?y f ?y h)
       '(a  b c  d  e f g  h))
nil
> (cmp '(?x b ?x d ?y f ?y h)
       '(a  b a  d  e f e  h))
t

ただし、すでに一致の関連付けリストから始めている場合、最初のリストは次のように呼び出されます。

> (cmp '(?x ?y)
       '(a  b)
       '((?x . a)))
t

2番目のものは次のように使用されますが:

> (let ((*matches* '((?x . a))))
    (cmp '(?x ?y)
         '(a  b)))
t

演習:cmp常に一致'?するようにします(名前が疑問符のみである記号)。

これは、要素をそこに配置したいが、それ以外の場合は無視したい場合に便利です。


演習:cmpより便利にし、次の代わりに見つかった関連付けのリストを返しますt

> (cmp '(?x ?y)
       '(a  b))
((?x . a)
 (?y . b))

;;; Assuming option one
> (cmp '(?x ?y)
       '(a  b)
       '((?x . a)
         (?z . c)))
((?x . a)
 (?y . b))
> (cmp '(?x ?y)
       '(c  b)
       '((?x . a)
         (?z . c)))
nil

アイデアは、見つかった関連付けのみを返し、未使用の関連付けは返さないことです。したがって、2番目のテストが非nilを返しても?z、結果には表示されません。

于 2012-11-17T00:48:03.190 に答える