LISP split recursive function

The split-list function takes a list and returns a list of two lists consisting of alternating input elements. I wrote the following:

(defun split-list (L)
  (cond
      ((endp L) (list NIL  NIL))
      (t (let ((X (split-list (cdr L))))
         (cond
             ((oddp (length L))
              (list (cons (first L) (first X)) (cadr X)))
             (t (list (first X) (cons (first L) (cadr X)))))))))

The output is expected for odd lists, the first list consisting of 1st, 3rd, 5th, etc. elements, and the second part consists of the 2nd, 4th, 6th, etc. However, with an even list, 1st, 2nd, 3rd .. are to the right of the returned lists, and the rest to the left.

Example:

(SPLIT-LIST '(a b c 1 2 3))
(SPLIT-LIST RETURNED ((b 1 3) (a c 2))

order should be replaced. Is there a major flaw in my logic that I'm missing? Can I fix this situation without making significant changes?

+4
source share
4 answers

, .

  • (endp (cdr L))
  • cddr L
  • else , ; length
+4

-, cond t, if.   , first, cadr; second , cadr.

. . , , . trace: (trace split-list). :

   0: (split-list (a b c 1 2 3))
    1: (split-list (b c 1 2 3))
      2: (split-list (c 1 2 3))
        3: (split-list (1 2 3))
          4: (split-list (2 3))
            5: (split-list (3))
              6: (split-list nil)
              6: split-list returned (nil nil)
            5: split-list returned ((3) nil)
          4: split-list returned ((3) (2))
        3: split-list returned ((1 3) (2))
      2: split-list returned ((1 3) (c 2))
    1: split-list returned ((b 1 3) (c 2))
  0: split-list returned ((b 1 3) (a c 2))

? :

   0: (split-list (a b c 1 2))
    1: (split-list (b c 1 2))
      2: (split-list (c 1 2))
        3: (split-list (1 2))
          4: (split-list (2))
            5: (split-list nil)
            5: split-list returned (nil nil)
          4: split-list returned ((2) nil)
        3: split-list returned ((2) (1))
      2: split-list returned ((c 2) (1))
    1: split-list returned ((c 2) (b 1))
  0: split-list returned ((a c 2) (b 1))

, !

:

(defun split-list (list)
  (if (endp list)
      '(nil nil)
      (destructuring-bind (left right) (split-list (cddr list))
        (list (cons (first list) left)
              (if (second list)
                  (cons (second list) right)
                  right)))))

. loop:

(defun split-list (list)
    (loop for (a b) on list by #'cddr
          collect a into left
          when b 
            collect b into right
          finally (return (list left right)))

, , 2 , , :

(defun split-list (list &optional (n 2))
  (loop with a = (make-array n :initial-element nil)
        for e in list
        for c = 0 then (mod (1+ c) n)
        do (push e (aref a c))
        finally (return (map 'list #'nreverse a))))

(split-list '(a b c d e f g) 3)
=> ((a d g) (b e) (c f))

, , , :

(defun split-n (sequence &optional (n 2))
  (let* ((ring (make-list n :initial-element nil))
         (head ring)
         (last (last ring)))
    (setf (cdr last) ring)
    (map nil
         (lambda (u)
           (push u (first ring))
           (pop ring))
         sequence)
    (setf (cdr last) nil)
    (map-into head #'nreverse head)))

, , (setf *print-circle* t).

+2

, , . . - , , . , ( ). , , , . "evens", , . , evens , . , , "" evens ands.

(defun split-list (list &optional (evens '()) (odds '()) (evenp t))
  "Returns a list of two lists, the even indexed elements from LIST
and the odd indexed elements LIST."
  (if (endp list)
      ;; If we're at the end of the list, then it time to reverse
      ;; the two lists that we've been building up.  Then, if we ended
      ;; at an even position, we can simply return (EVENS ODDS), but
      ;; if we ended at an odd position, we return (ODDS EVENS).
      (let ((odds (nreverse odds))
            (evens (nreverse evens)))
        (if evenp
            (list evens odds)
            (list odds evens)))
      ;; If we're not at the end of the list, then we add the first
      ;; element of LIST to EVENS, but in the recursive call, we swap
      ;; the position of EVENS and ODDS, and we flip the EVENP bit.
      (split-list (rest list)
                  odds
                  (list* (first list) evens)
                  (not evenp))))

CL-USER> (split-list '())
(NIL NIL)
CL-USER> (split-list '(1))
((1) NIL)
CL-USER> (split-list '(1 2))
((1) (2))
CL-USER> (split-list '(1 2 3))
((1 3) (2))
CL-USER> (split-list '(1 2 3 4))
((1 3) (2 4))
CL-USER> (split-list '(1 2 3 4 5 6 7 8 9 10))
((1 3 5 7 9) (2 4 6 8 10))
+1

- , , . , , .

, ( - Lisp, ?), Racket , . , .

/ , !

( "" Haskell)

    foldr (\x [a,b] -> [x:b,a]) [[],[]] 

F # (IIRC) ed'ka (IIRC); , . , , .

,

(define (split xs)
  (cond
    ((null? xs) (list '() '()))
    ((split (cdr xs)) => (lambda (acc) 
         (list (cons (car xs) (cadr acc))   ; always in the first subgroup!
               (car acc))))))               

. , , , , , , , - , ;!

(split '(a b c 1 2 3))
(split '(a b c 1 2))

; '((a c 2) (b 1 3))
; '((a c 2) (b 1))

: if , cond, if - , , . cond , .


It’s easy enough to change this to get, for example, tripartite separation, with

(define (split3 xs)
  (cond
    ((null? xs) (list '() '() '()))
    (else (apply
           (lambda (a b c)             ; Scheme-style destructuring
             (list (cons (car xs) c)   ; rotate right:
                   a                   ;   xs 2nd elt to appear in the 2nd group!
                   b))                 ;   head element of (cdr xs) is in `a`
           (split3 (cdr xs))))))       ; the recursive result

(split3 '(a b c 1 2 3))
(split3 '(a b c 1 2))

; '((a 1) (b 2) (c 3))
; '((a 1) (b 2) (c))
+1
source

Source: https://habr.com/ru/post/1612836/


All Articles