我有两个清单:
(setq x (list "a" "b" "c"))
(setq y (list "1" "2" "3" "4"))
如何创建一个(("a" . "1") ("b" . "2") ("c" . "3") ("a" . "4"))
回收较短列表的缺点单元列表?
我有两个清单:
(setq x (list "a" "b" "c"))
(setq y (list "1" "2" "3" "4"))
如何创建一个(("a" . "1") ("b" . "2") ("c" . "3") ("a" . "4"))
回收较短列表的缺点单元列表?
这是我的看法:
(require 'cl-lib)
(cl-mapcar #'list (setcdr (last x) x) y)
我会检查其中哪个更大,但这会破坏简洁性:)。
肯定有一种更简单的方法可以做到这一点,但这里有一个版本,它将输入序列转换为无限列表并将它们压缩在一起:
(defun* cycle-iterator (xs &optional (idx 0) (len (length xs)))
"Create an iterator that will cycle over the elements in XS.
Return a cons, where the car is the current value and the cdr is
a function to continue the iteration."
(cons (nth (mod idx len) xs)
(eval `(lambda () (cycle-iterator ',xs ,(1+ idx) ,len)))))
(defun cycle-take (xs n)
"Take N elements from XS, cycling the elements if N exceeds the length of XS."
(loop
when (plusp n)
;; Creating the iterator returns the first value. Subsequent calls can then
;; be processed in a loop.
with (value . iterator) = (cycle-iterator xs)
with acc = (list value)
repeat (1- n) do (destructuring-bind (val . next) (funcall iterator)
(setq iterator next)
(setq acc (cons val acc)))
finally (return (nreverse acc))))
(defun cycling-zip (xs ys)
"Zip XS and YS together, cycling elements to ensure the result
is as long as the longest input list."
(loop
with limit = (max (length xs) (length ys))
for x in (cycle-take xs limit)
for y in (cycle-take ys limit)
collect (cons x y)))
;; Usage:
(cycling-zip '("a" "b" "c") '("1" "2" "3" "4"))
; => (("a" . "1") ("b" . "2") ("c" . "3") ("a" . "4"))
这个答案需要dash
列表操作库。在解决您的问题之前,最好找到最长列表的长度。我想出的第一种方法是:
(require 'dash)
(require 'dash-functional)
(length (-max-by (-on '> 'length) (list x y))) ; 4
-on
是一个来自包的智能函数,dash-functional
它接受一个比较器,一个要比较的键,并返回一个在这个键上进行比较的函数。因此在中找到一个长度最大(-max-by (-on '> 'length) xs)
的元素。但是这个表达式本身就太聪明了,由于词法作用域,只能在 Emacs 24 中工作。让我们重写它,灵感来自Python 解决方案:xs
dash-functional
(-max (-map 'length (list x y))) ; 4
要从n
无限循环列表中获取第一个元素,请执行(-take n (-cycle xs))
. 因此,要创建一个 alist,其中循环来自较小列表的元素,请编写:
(let ((len (-max (-map 'length (list x y)))))
(flet ((cycle (xs) (-take len (-cycle xs))))
(-zip (cycle x) (cycle y)))) ; (("a" . "1") ("b" . "2") ("c" . "3") ("a" . "4"))
我采用了对 lisp 来说似乎很自然的递归方法。
(defun zip (xs ys)
(cond
((or (null xs) (null ys)) ())
(t (cons (cons (car xs) (car ys)) (zip (cdr xs) (cdr ys))))))