方案:将列表拆分为偶数和奇数位置的两个子列表的列表

时间:2015-01-17 01:47:42

标签: scheme racket

我正在尝试使用直接递归将列表排序为偶数和奇数位置的子列表列表。

所以(分裂'(1 2 3 4 5 6))返回((1 3 5)(2 4 6))

和(split'(a 2 b 3))返回((a b)(2 3))

到目前为止,我有以下代码:

(define split
  (lambda (ls)
    (if (or (null? ls) (null? (cdr ls))) 
        (values ls '())
        (call-with-values
          (lambda () (split (cddr ls)))
          (lambda (odds evens)
            (values (cons (car ls) odds)
                    (cons (cadr ls) evens)))))))

然而,现在我对如何将多个输出存储到单个列表感到困惑。

我知道这样称呼它:

(call-with-values (lambda () (split '(a b c d e f))) list)

返回一个子列表列表,但是我希望函数本身返回一个子列表列表。有没有更好的方法来做到这一点,不涉及使用值和调用值?

4 个答案:

答案 0 :(得分:4)

不确定。这是您的代码的改编版本:

(define (split ls)
  (if (or (null? ls) (null? (cdr ls)))
      (list ls '())
      (let ((next (split (cddr ls))))
        (list (cons (car ls) (car next))
              (cons (cadr ls) (cadr next))))))

答案 1 :(得分:0)

我喜欢问题代码的一件事是,它以反映规范的方式使用oddsevens

此解决方案的目标是:

  1. 可读性。

  2. 在代码中反映规范的语言。

  3. 在执行期间使用O(n)空格。

  4. 它使用带累加器和蹦床的内部功能。

    #lang racket
    
    ;; List(Any) -> List(List(Any) List(Any))
    (define (split list-of-x)
    
      (define end-of-list (length list-of-x))
    
      ;;  List(Any) List(Any) List(Any) Integer -> List(List(Any) List(Any))
      (define (looper working-list odds evens index)
        (cond [(> index end-of-list)
               (list (reverse odds)
                     (reverse evens))]
              [(odd? index)
               (looper (rest working-list)
                       (cons (car working-list) odds)
                       evens
                       (add1 index))]
              [(even? index)
               (looper (rest working-list)
                       odds
                       (cons (car working-list) evens)
                       (add1 index))]
              [else
               (error "split: unhandled index condition")]))
    
      (looper list-of-x null null 1))
    

答案 2 :(得分:0)

如果您熟悉match语法,那么这个答案应该很清楚。它在形式和功能上与Chris Jester-Young的答案完全相同,但使用match来澄清列表操作。

#lang racket

(define (split ls)
  (match ls
    [`(,first ,second ,rest ...) 
     (match (split rest)
       [`(,evens ,odds) (list (cons first evens)
                              (cons second odds))])]
    [_ (list ls '())]))

答案 3 :(得分:0)

(: split ((list-of natural) -> (list-of (list-of natural))))
(define split
  (lambda (xs)
    (list (filter even? xs) (filter odd? xs))))

(: filter ((%a -> boolean) (list-of %a) -> (list-of %a)))
(define filter
  (lambda (p xs)
   (fold empty (lambda (first result)
                   (if (p first)
                       (make-pair first result)
                       result)) xs)))

(check-expect (split (list 1 2 3 4 5 6)) (list (list 2 4 6) (list 1 3 5)))

我认为这真的很容易理解。