LISP(将列表中间的值加一)
LISP (Add one to the value in the middle of the list)
我目前正在尝试创建一个函数,将列表中间的值加 1。
Example: (add1 '(2 4 6 5 9)) -> (2 4 7 5 9)
此外,如果列表是偶数,则 returns 没有。到目前为止,我有一个函数 returns 列表中间的位置。
(defun add1(aList)
(if (oddp (length aList)) (- (/ (length aList) 2) .5) 'EvenNumber))
示例:(add1 '(2 4 6 5 9)) -> 2.0
有没有办法利用这些信息得到中间的值然后加1。谢谢
给你:
(defun add-1 (list)
(let ((len (length list)))
(assert (oddp len) (list))
(incf (nth (/ (1- len) 2) list))))
尝试这样的事情。
(defun add1 (lst)
(when (oddp (length lst))
(incf (nth (floor (/ (length lst) 2)) lst)))
lst)
我认为您需要的缺失部分是 setf
(您可能已经使用过它,但也许您不知道可以使用 form第一个参数)或在本例中为 incf
(增加一个或可选的指定增量)。它们允许您使用表达式来获取需要设置的值。
一些需要思考的事情(如所写):
- 这是一个破坏性更新
- 它在同一个列表上多次调用
length
。这可能很昂贵。
- 如我所写,偶数长度列表只是 return 列表不变。这不完全是您要求的,但也许是您想要的。
- 我使用
floor
而不是乱用减法 .5
,这将需要一些额外的转换。
这是一个函数,它只对列表进行两次传递而不是修改原始列表,并且不对整数执行任何算术运算:
(defun inc-middle-elt (list)
(loop for elem in list
for pair = list then (cddr pair)
with flag = t
when (and flag (null (cddr pair))) do
(if (null (cdr pair))
(incf elem))
(setf flag nil)
collect elem))
为了找到中间点,这使用了与链表的二进制合并排序实现中使用的技巧类似的技巧:辅助指针 pair
双步遍历列表,跨对。
当 (cddr pair)
是 nil
时,我们处于最后一对。那时,必须做出决定:列表中的项目数是否为奇数?如果列表有奇数个项目,那么在最后一对位置,(cddr pair)
是 nil
,只剩下一个元素:(cdr pair)
也是 nil。
练习:利用链表中部之后的元素不需要复制的特点优化这个函数;输出列表可以共享输入列表的尾部。另外,更改函数,以便在清楚没有中间元素时,它 returns 原始列表。
我希望您正在寻找 递归版本,
(defun middle (lis)
(let ((lis (c-in-place lis)))
(cond ((null lis) nil) ((atom lis) lis)
(t
(mapcar
#'(lambda (x)
(cond ((atom x) x) (t (mapcar #'c-in-place (c-in-place x)))))
lis)))))
(defun c-in-place (lis)
(cond
((and (listp lis) (oddp (length lis)) (> (length lis) 2))
(let ((pos (1+ (floor (/ (length lis) 2)))))
(in-place (1+ (nth (floor (/ (length lis) 2)) lis)) pos lis)))
(t lis)))
(defun in-place (nxt n lis)
(let (temp temp1) (setf temp (subseq lis 0 (- n 1)))
(setf temp1 (subseq lis n)) (setf temp (append temp (append `(,nxt) temp1)))
temp))
用法:
(middle '((1 4 6 7 8) (3 4 2)))
=>((1 4 7 7 8) (3 5 2))
(middle '((1 4 6 7) (3 4 2)))
=> ((1 4 6 7) (3 5 2))
(middle '(2 3 4))
=> (2 4 4)
(middle '(2 3 4 5)
=> (2 3 4 5)
我目前正在尝试创建一个函数,将列表中间的值加 1。
Example: (add1 '(2 4 6 5 9)) -> (2 4 7 5 9)
此外,如果列表是偶数,则 returns 没有。到目前为止,我有一个函数 returns 列表中间的位置。
(defun add1(aList)
(if (oddp (length aList)) (- (/ (length aList) 2) .5) 'EvenNumber))
示例:(add1 '(2 4 6 5 9)) -> 2.0
有没有办法利用这些信息得到中间的值然后加1。谢谢
给你:
(defun add-1 (list)
(let ((len (length list)))
(assert (oddp len) (list))
(incf (nth (/ (1- len) 2) list))))
尝试这样的事情。
(defun add1 (lst)
(when (oddp (length lst))
(incf (nth (floor (/ (length lst) 2)) lst)))
lst)
我认为您需要的缺失部分是 setf
(您可能已经使用过它,但也许您不知道可以使用 form第一个参数)或在本例中为 incf
(增加一个或可选的指定增量)。它们允许您使用表达式来获取需要设置的值。
一些需要思考的事情(如所写):
- 这是一个破坏性更新
- 它在同一个列表上多次调用
length
。这可能很昂贵。 - 如我所写,偶数长度列表只是 return 列表不变。这不完全是您要求的,但也许是您想要的。
- 我使用
floor
而不是乱用减法.5
,这将需要一些额外的转换。
这是一个函数,它只对列表进行两次传递而不是修改原始列表,并且不对整数执行任何算术运算:
(defun inc-middle-elt (list)
(loop for elem in list
for pair = list then (cddr pair)
with flag = t
when (and flag (null (cddr pair))) do
(if (null (cdr pair))
(incf elem))
(setf flag nil)
collect elem))
为了找到中间点,这使用了与链表的二进制合并排序实现中使用的技巧类似的技巧:辅助指针 pair
双步遍历列表,跨对。
当 (cddr pair)
是 nil
时,我们处于最后一对。那时,必须做出决定:列表中的项目数是否为奇数?如果列表有奇数个项目,那么在最后一对位置,(cddr pair)
是 nil
,只剩下一个元素:(cdr pair)
也是 nil。
练习:利用链表中部之后的元素不需要复制的特点优化这个函数;输出列表可以共享输入列表的尾部。另外,更改函数,以便在清楚没有中间元素时,它 returns 原始列表。
我希望您正在寻找 递归版本,
(defun middle (lis)
(let ((lis (c-in-place lis)))
(cond ((null lis) nil) ((atom lis) lis)
(t
(mapcar
#'(lambda (x)
(cond ((atom x) x) (t (mapcar #'c-in-place (c-in-place x)))))
lis)))))
(defun c-in-place (lis)
(cond
((and (listp lis) (oddp (length lis)) (> (length lis) 2))
(let ((pos (1+ (floor (/ (length lis) 2)))))
(in-place (1+ (nth (floor (/ (length lis) 2)) lis)) pos lis)))
(t lis)))
(defun in-place (nxt n lis)
(let (temp temp1) (setf temp (subseq lis 0 (- n 1)))
(setf temp1 (subseq lis n)) (setf temp (append temp (append `(,nxt) temp1)))
temp))
用法:
(middle '((1 4 6 7 8) (3 4 2)))
=>((1 4 7 7 8) (3 5 2))
(middle '((1 4 6 7) (3 4 2)))
=>((1 4 6 7) (3 5 2))
(middle '(2 3 4))
=>(2 4 4)
(middle '(2 3 4 5)
=>(2 3 4 5)