如何将列表转换为子列表?
How to transform list into sub lists?
((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
来自
(1 2 3 4 5 6)
这种操作的类型是什么?
我尝试了什么:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
您每次循环都推送相同的子列表。
您可以使用 :for sublist on
循环列表的连续尾部。
并使用 :collect
列出所有结果,而不是推入您自己的列表
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
或者使用 map
:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
您可以将其解读为:
- 列表
l
的值为 (1 2 3 4 5 6)
map
遍历列表及其两个连续的 cdr
s
- 通过对列表的元素应用
#'list
map
并行循环
- (最短列表用完停止)
- 并收集结果 as/into a
'list
@WillNess 建议更简单:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
谢谢!那么我们可以仅使用 map
变体进行概括:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l)
等价于 (loop for sl on l collect sl)
。
然而,
(loop for sl on l
for i from 0 to n
collect sl)
更好,因为它在第 n 轮循环时停止...
这是 Barmar 答案的一个版本(应该是公认的),它更通用一些,只调用 length
一次。
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
首先让我们定义一个函数take-n
,如果没有足够的项目,它要么是returns n 个项目,要么是一个空列表。它不会扫描整个列表。
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
然后我们将此函数 take-n
移动到列表中,直到 returns NIL
.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
示例:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
或者更经典的C
-like for-loop-ing with indexes来解决它。
但是在strings/vectors上用的多,在列表上用的少,因为它的性能是
- 对于二次列表
- 用于向量(字符串!)线性,因此最好与它们一起使用!
感谢 @WillNess 指出了这两点(见下面的评论)。
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
所以 vectors/strings 使用:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")
((1 2 3)
(2 3 4)
(3 4 5)
(4 5 6))
来自
(1 2 3 4 5 6)
这种操作的类型是什么?
我尝试了什么:
(loop
:with l2 = '()
:with l1 = '(1 2 3 4 5 6)
:for i :in l1
:do (push (subseq l1 0 3) l2))
您每次循环都推送相同的子列表。
您可以使用 :for sublist on
循环列表的连续尾部。
并使用 :collect
列出所有结果,而不是推入您自己的列表
(loop
:for l1 on '(1 2 3 4 5 6)
:if (>= (length l1) 3)
:collect (subseq l1 0 3)
:else
:do (loop-finish))
或者使用 map
:
(let ((l '(1 2 3 4 5 6)))
(map 'list #'list l (cdr l) (cddr l)))
;; ((1 2 3) (2 3 4) (3 4 5) (4 5 6))
您可以将其解读为:
- 列表
l
的值为(1 2 3 4 5 6)
map
遍历列表及其两个连续的cdr
s- 通过对列表的元素应用
#'list
map
并行循环 - (最短列表用完停止)
- 并收集结果 as/into a
'list
@WillNess 建议更简单:
(let ((l '(1 2 3 4 5 6)))
(mapcar #'list l (cdr l) (cddr l)))
谢谢!那么我们可以仅使用 map
变体进行概括:
(defun subseqs-of-n (l n)
(apply #'mapcar #'list (subseq (maplist #'identity l) 0 n)))
(maplist #'identity l)
等价于 (loop for sl on l collect sl)
。
然而,
(loop for sl on l
for i from 0 to n
collect sl)
更好,因为它在第 n 轮循环时停止...
这是 Barmar 答案的一个版本(应该是公认的),它更通用一些,只调用 length
一次。
(defun successive-leading-parts (l n)
(loop repeat (1+ (- (length l) n))
for lt on l
collect (subseq lt 0 n)))
> (successive-leading-parts '(1 2 3 4) 3)
((1 2 3) (2 3 4))
> (successive-leading-parts '(1 2 3 4) 2)
((1 2) (2 3) (3 4))
首先让我们定义一个函数take-n
,如果没有足够的项目,它要么是returns n 个项目,要么是一个空列表。它不会扫描整个列表。
(defun take-n (n list)
(loop repeat n
when (null list) return (values nil nil)
collect (pop list)))
然后我们将此函数 take-n
移动到列表中,直到 returns NIL
.
(defun moving-slice (n list)
(loop for l on list
for p = (take-n n l)
while p
collect p))
示例:
CL-USER 207 > (moving-slice 3 '(1 2))
NIL
CL-USER 208 > (moving-slice 3 '(1 2 3))
((1 2 3))
CL-USER 209 > (moving-slice 3 '(1 2 3 4 5 6 7))
((1 2 3) (2 3 4) (3 4 5) (4 5 6) (5 6 7))
或者更经典的C
-like for-loop-ing with indexes来解决它。
但是在strings/vectors上用的多,在列表上用的少,因为它的性能是
- 对于二次列表
- 用于向量(字符串!)线性,因此最好与它们一起使用!
感谢 @WillNess 指出了这两点(见下面的评论)。
(defun subseqs-of-n (ls n) ;; works on strings, too!
(loop :for i :from 0 :to (- (length ls) n)
:collect (subseq ls i (+ i n))))
所以 vectors/strings 使用:
(subseqs-of-n "gattaca" 5)
;; ("gatta" "attac" "ttaca")