Lisp - 将列表拆分为 n 个列表

Tru*_*lv1 2 lisp functional-programming common-lisp

我想不出如何平均分割列表的方法,例如这个列表:

(("6" "S") ("7" "S") ("8" "S") ("9" "S") ("10" "S") ("J" "S") ("K" "S")
 ("A" "S") ("6" "C") ("7" "C") ("8" "C") ("9" "C") ("10" "C") ("J" "C")
 ("Q" "C") ("K" "C") ("A" "C") ("6" "H") ("7" "H") ("8" "H") ("9" "H")
 ("10" "H") ("J" "H") ("Q" "H") ("K" "H") ("A" "H")("6" "D") ("7" "D")
 ("8" "D") ("9" "D") ("10" "D") ("J" "D") ("Q" "D") ("K" "D"))
Run Code Online (Sandbox Code Playgroud)

分成n列表,例如在 3 个或 4 个列表中,具体取决于需要拆分的数量。如果在 3 个列表中,则应返回的列表应如下所示:

(("6" "S") ("7" "S") ("8" "S") ("9" "S") ("10" "S") ("J" "S") ("K" "S")
 ("A" "S") ("6" "C") ("7" "C") ("8" "C") ("9" "C"))
(("10" "C") ("J" "C") ("Q" "C") ("K" "C") ("A" "C")("6" "H") ("7" "H")
 ("8" "H") ("9" "H") ("10" "H") ("J" "H") ("Q" "H"))
(("K" "H") ("A" "H")("6" "D") ("7" "D") ("8" "D") ("9" "D") ("10" "D")
 ("J" "D") ("Q" "D") ("K" "D"))
Run Code Online (Sandbox Code Playgroud)

第一个列表将包含 12 个元素,第二个列表包含 12 个元素,第三个列表包含 11 个元素。

ram*_*ner 5

如果您研究方案的接受和删除功能,您可以实现您想要的。例如,观察这个简单的过程:

(define (splitparts lst num)
  (letrec ((recurse
            (lambda (lst num acc)
              (if (null? lst)
                acc
                (recurse (drop lst num) num (append acc (list (take lst num))))))))
    (recurse lst num '())))

> (splitparts '(1 2 3 4) 2)
((1 2) (3 4))
> (splitparts '(1 2 3 4 5 6 7 8) 2)
((1 2) (3 4) (5 6) (7 8))
Run Code Online (Sandbox Code Playgroud)

现在的问题是,如果采取和删除,您希望列表至少具有您所请求的元素数量。因此我们可以编写自己的版本,该版本需要一定数量的元素,如果元素数量较少,他们也不在乎。这是受此线程启发的 take 实现,具有正确的尾递归实现

(define (takeup to lst)
  (letrec ((recurse
           (lambda (to lst acc)
             (if (or (zero? to) (null? lst))
               acc
               (recurse (- to 1) (cdr lst) (append acc (list (car lst))))))))
    (recurse to lst '())))

> (takeup 5 '(1 2 3))
(1 2 3)
> (takeup 5 '(1 2 3 4 5 6 7))
(1 2 3 4 5)
Run Code Online (Sandbox Code Playgroud)

现在,当您实现类似的 dropupto 函数时,您可以轻松编写 splitparts 函数。在 Common Lisp 中,您可以使用subseq函数来实现类似于 take 和 drop 的功能。

编辑:简单 take 和 drop 的常见 lisp 实现(请原谅我非常不惯用的 CL)

;; recursive implemention of take just for demo purposes.
(defun takeinner (lst num acc)
  (if (or (= num 0) (null lst))
    acc
    (takeinner (cdr lst) (- num 1) (append acc (list (car lst))))))

(defun take (lst num)
  (takeinner lst num '()))

;; of course take can be implemented using subseq as drop.
(define take-alternative (lst num)
  (subseq lst 0 num))

(defun drop (lst num)
  (subseq lst num))

(defun splitpartsinner (lst num acc)
   (if (null lst)
        acc
       (splitpartsinner (drop lst num) num (append acc (list (take lst num))))))

(defun splitparts (lst num)
  (splitpartsinner lst num '()))

> (splitparts '(1 2 3 4) 2)
((1 2) (3 4))
Run Code Online (Sandbox Code Playgroud)

这将受到上述问题的影响,因此您仍然必须实现 -up-to 版本。