公共Lisp中最大的子列表
我正在尝试使用CommonLisp从列表中获取最大的子列表公共Lisp中最大的子列表,lisp,common-lisp,Lisp,Common Lisp,我正在尝试使用CommonLisp从列表中获取最大的子列表 (defun maxlist (list) (setq maxlen (loop for x in list maximize (list-length x))) (loop for x in list (when (equalp maxlen (list-length x)) (return-from maxlist x))) ) 其思想是迭代列表两次:第一个循环获取最大子列表的大小,第二个循环检索所需列表。但是由于某种原因,我在从
(defun maxlist (list)
(setq maxlen (loop for x in list maximize (list-length x)))
(loop for x in list (when (equalp maxlen (list-length x)) (return-from maxlist x)))
)
其思想是迭代列表两次:第一个循环获取最大子列表的大小,第二个循环检索所需列表。但是由于某种原因,我在从行返回的中不断收到一个错误。我错过了什么 循环的主要问题
这里有一些问题。首先,您可以按如下方式编写循环。在Common Lisp中有return from
和while
表单,但定义了自己的小语言,它也可以识别while
和return
,因此您可以使用它们:
(列表中x的循环
当(相等最大长度(列表长度x))
返回x)
不过,使用find
实际上可以更简洁地编写这样的循环。只是
(查找最大列表:键列表长度:测试'equalp》)
但是,请注意,list length
应始终返回一个数字或nil
,因此equalp
是多余的。您只需使用eql
,这是find
的默认值,因此您甚至可以编写
(查找最大列表:键列表长度)
列表长度
和最大化
list length
与length
非常相似,不同的是,如果列表具有循环结构,则返回nil
,而使用不正确的列表调用length
则是错误的。但是如果使用的是(循环…最大化…
),则不能有nil
值,因此列表长度
处理长度
的唯一情况是仍然会给您一个错误。例如:
CL-USER>(循环用于x英寸(4-3零)最大化x)
; 对#的评估已中止。
(实际上,length
也适用于其他类型的序列,因此如果传递向量,list length
将出错,但length
不会)。因此,如果您知道它们都是正确的列表,您可以
(列表中x的循环
最大化(长度x))
如果它们不一定都是正确的列表(因此您确实需要列表长度
),那么您需要进行如下保护:
(列表中x的循环
对于len=(列表长度x)
除非(空len)最大化len)
更高效的argmax
但是,现在您要对列表进行两次遍历,并且要计算每个子列表的长度两次。一次是计算最大长度,另一次是查找具有最大值的长度。如果你一次完成,你会节省时间argmax
没有一个明显的优雅解决方案,但这里有一些基于reduce
、loop
和do*
的实现
(defun argmax(fn列表和键(谓词“>)(键”标识))
(解构绑定(第一个和第二个)列表
(轿厢(减小(λ)(最大xv x)
(解构绑定(maxx.maxv)maxxxv
(声明(忽略maxx))
(let((v(funcall-fn(funcall-key x)))
(如果(funcall谓词v maxv)
(十、五)
maxxv)))
休息
:初始值(cons优先(funcall fn(funcall键优先‘‘‘‘‘‘‘)’))
(defun argmax(函数列表和键(谓词“>)(键标识))
(环路
对于列表中的x
对于v=(funcall函数(funcall键x))
对于maxx=x,则为maxx
对于maxv=v,则为maxv
when(funcall谓词v maxv)
do(setq最大值x)
最大值(v)
最后(返回maxx)))
(defun argmax(函数列表和键(谓词“>)(键标识))
(do*((x(流行音乐列表)
(流行音乐列表)
(v(funcall函数(funcall键x))
(funcall函数(funcall键x)))
(最大值x)
(maxv)
((endp列表)maxx)
(当(funcall谓词v maxv)
(setq最大值x)
maxv(v)))
它们产生相同的结果:
CL-USER>(argmax'length'((1 2 3)(4 5)(6 7 8 9)))
(6 7 8 9)
CL-USER>(argmax'length'((1 2 3)(6 7 8 9)(4 5)))
(6 7 8 9)
CL-USER>(argmax'length'((6789)(12345)))
(6 7 8 9)
循环的主要问题
这里有一些问题。首先,您可以按如下方式编写循环。在Common Lisp中有return from
和while
表单,但定义了自己的小语言,它也可以识别while
和return
,因此您可以使用它们:
(列表中x的循环
当(相等最大长度(列表长度x))
返回x)
不过,使用find
实际上可以更简洁地编写这样的循环。只是
(查找最大列表:键列表长度:测试'equalp》)
但是,请注意,list length
应始终返回一个数字或nil
,因此equalp
是多余的。您只需使用eql
,这是find
的默认值,因此您甚至可以编写
(查找最大列表:键列表长度)
列表长度
和最大化
list length
与length
非常相似,不同的是,如果列表具有循环结构,则返回nil
,而使用不正确的列表调用length
则是错误的。但是如果使用的是(循环…最大化…
),则不能有nil
值,因此列表长度
处理长度
的唯一情况是仍然会给您一个错误。例如:
CL-USER>(循环用于x英寸(4-3零)最大化x)
; 对#的评估已中止。
(实际上,length
也适用于其他类型的序列,因此如果传递向量,list length
将出错,但length
不会)。因此,如果您知道它们是
CL-USER> (defparameter *test* '((1 2 3) (4 5) (6 7 8 9)))
*TEST*
CL-USER> (car (sort *test* '> :key #'length))
(6 7 8 9)
(defun most (fn lst)
(if (null lst)
(values nil nil)
(let* ((wins (car lst))
(max (funcall fn wins)))
(dolist (obj (cdr lst))
(let ((score (funcall fn obj)))
(when (> score max)
(setq wins obj
max score))))
(values wins max))))
CL-USER> (most #'length *test*)
(6 7 8 9)
4
(declaim (inline use-key))
(defun use-key (key arg)
(if key (funcall key arg) arg))
(defun extreme (fn lst &key key)
(let* ((win (car lst))
(rec (use-key key win)))
(dolist (obj (cdr lst))
(let ((test (use-key key obj)))
(when (funcall fn test rec)
(setq win obj rec test))))
(values win rec)))
CL-USER> (extreme #'> '(4 9 2 1 5 6))
9
9
CL-USER> (extreme #'< '(4 9 2 1 5 6))
1
1
CL-USER> (extreme #'> '((1 2 3) (4 5) (6 7 8 9)) :key #'length)
(6 7 8 9)
4
CL-USER> (extreme #'> '((1 2 3) (4 5) (6 7 8 9)) :key #'cadr)
(6 7 8 9)
7
(defun maxim-list (l)
(flet ((max-list (a b) (if (> (length a) (length b)) a b)))
(if (null l)
nil
(max-list (car l) (maxim-list (cdr l))))))