6

我有两个清单:

(setq x (list "a" "b" "c"))
(setq y (list "1" "2" "3" "4"))

如何创建一个(("a" . "1") ("b" . "2") ("c" . "3") ("a" . "4"))回收较短列表的缺点单元列表?

4

4 回答 4

6

这是我的看法:

(require 'cl-lib)
(cl-mapcar #'list (setcdr (last x) x) y)

我会检查其中哪个更大,但这会破坏简洁性:)。

于 2013-07-23T14:40:16.087 回答
1

肯定有一种更简单的方法可以做到这一点,但这里有一个版本,它将输入序列转换为无限列表并将它们压缩在一起:

(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"))
于 2013-07-23T01:11:01.327 回答
1

这个答案需要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 解决方案xsdash-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"))
于 2014-08-04T10:18:39.663 回答
0

我采用了对 lisp 来说似乎很自然的递归方法。

(defun zip (xs ys)
  (cond
   ((or (null xs) (null ys)) ())
   (t (cons (cons (car xs) (car ys)) (zip (cdr xs) (cdr ys))))))
于 2015-11-30T00:50:10.640 回答