使用通配符比较列表 [英] compare lists using wild cards

查看:89
本文介绍了使用通配符比较列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个将两个列表进行作业比较的函数.当函数运行时应该是这样;(cmp'(cat?x mat?x)'(cat bat mat bat))=> t;(cmp'(cat?x mat?x)'(cat bat mat坐))=>无.这意味着在第一个列表中等于?x的列表中,如果第二个xx都指向相同的值,则返回true. 现在,当我运行程序时,给我如果解析特殊形式的参数时出错:元素数量无效"如果可以给我一些反馈,这是我的代码.谢谢.

I am trying to write a function which compares two lists for homework. When the function run it should be something like this ;(cmp ‘(cat ?x mat ?x) ‘(cat bat mat bat)) => t ;(cmp ‘(cat ?x mat ?x) ‘(cat bat mat sat)) => nil. meaning that in the first list when equal to ?x and the second ?x return true if both are pointing to the same value. When I run the program now is giving me "error while parsing arguments to special form if: invalid number of elements" Here is my code if you can give me some feedback. Thanks.

;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

推荐答案

您快到了.您缺少如何在第一个字符为?的任何符号上进行一般匹配,以及如何将匹配传递给递归调用.

You're almost there. You're missing how to match generically on any symbol whose first character is ? and how to pass matches to recursive calls.

您需要将匹配项保存在两次呼叫之间的某个位置.一种可行的方法是在匹配的可选关联列表中传递它们:

You need to save your matches somewhere between calls. A possible approach is pass them in an optional association list of matches:

(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))))

与此方法非常相似,它使用动态变量 :

A very similar approach to this one which uses a dynamic variable:

(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

但是,如果您已经从匹配项的关联列表开始,则第一个名称将如下所示:

However, if you already start with an association list of matches, the first one is called like this:

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

第二个像这样使用时:

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


锻炼:使cmp始终与'?(名称仅是问号的符号)匹配.


Exercise: Make cmp always match '? (a symbol whose name is solely the question mark) to anything.

如果您想在其中放置一个元素,但又想忽略它,这可能会很有用.

This may be useful if you want an element to be there but you want to ignore it otherwise.

锻炼:使cmp更有用,并返回找到的关联的列表,而不是t:

Exercise: Make cmp more useful and return the list of found associations instead of 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

这个想法是只返回找到的关联,而不返回未使用的关联.因此,即使第二个测试返回非nil,结果中也不会出现?z.

The idea is to return only the found associations, and not the unused ones. So, even though the second test returns non-nil, ?z doesn't appear in the result.

这篇关于使用通配符比较列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆