我想使用(cl-every #'eq list1 list2)
比较 elisp 中的两个列表。但是,如果其中一个列表比另一个列表长,这可能会返回t
,我不希望这样。我可以在列表中调用length
,但是我遍历每个列表两次,这是不必要的低效。有没有像cl-every
这样的函数也可以检查相等的长度?
OOTB
我不认为有这样的功能 OOTB。
自己动手
我认为实现一个并不难,只需修改cl-every
.
长度
请注意,length
是用 C 实现的,除非您的列表很大,否则不会明显影响性能:
(defun list-elements-eq (l1 l2)
(and (= (length l1)
(length l2))
(every #'eq l1 l2)))
平等
您还可以将equal
用于列表:由于equal
从测试eq
开始,因此它将是一个比您想要的更弱的关系。
请注意,在 Common Lisp 中,equal
可能不会终止于循环结构。 Emacs Lisp "更智能":它可以检测 cicularity:
(setq x (list 1))
(setcdr x x)
(setq y (list 1))
(setcdr y y)
(eq x y)
(equal x y)
Debugger entered--Lisp error: (circular-list #1=(1 . #1#))
equal(#1=(1 . #1#) #2=(1 . #2#))
(可以说,它应该返回t
(。
Common Lisp
一般来说,Common Lisp 是"繁重工作"的更好语言。
如果你的列表很大,你可能想使用它而不是Emacs Lisp:
(defun list-elements-eq (l1 l2)
(if (endp l1)
(endp l2)
(and (not (endp l2))
(eq (pop l1) (pop l2))
(list-elements-eq l1 l2))))
这是尾递归的,任何像样的 CL 都会优化递归(可能取决于optimize
设置(。
你不想在 ELisp 中使用深度递归(参见为什么 Emacs lisp 中没有尾递归优化,而不是像其他方案一样?(。