在方案中将列表分区创建为三个部分

时间:2018-04-02 22:48:20

标签: list scheme racket partitioning r5rs

我试图找到一种方法将列表分成三部分。我使用了一个辅助函数,参数应该如下:它评估为三个列表的列表,包含1)列表中的项目少于枢轴,2)列表中的项目等于枢轴,3)列表中的项目大于pivot。

(define (partition lst item)
  (define (partition-iter lst less same greater)
   (cond ((null? lst)(list less same greater ))
      ((< (car lst) item)(partition-iter (cdr lst)
                                         (cons (car lst) less)
                                         same
                                         greater ))
      ((= (car lst) item)
       less
       (cons (car lst) same)
       (else
        (partition-iter (cdr lst) (cons (car lst) greater))))))
(partition-iter lst '() '() '()))    

除了else子句之外的所有内容都应该可以工作但是之后我就卡住了。任何帮助表示赞赏

2 个答案:

答案 0 :(得分:1)

当前辅助函数partition-iter由于其设计中的一些严重错误而无法工作。但首先,让我提供两个有用的版本:

第一个(简单)版本,

#lang racket

; LoN = List-of-Numbers

; partition :: LoN Number -> List-of-LoN
(define (partition1 lst pivot)
  (local([; auxiliary function
          ; part :: LoN LoN LoN LoN -> List-of-LoN
          define (part xs LT EQ GT)
          ; if empty list
          (if (null? xs) (list LT EQ GT)
              ;else
              (let* ([head (first xs)]
                     [tail (rest  xs)]
                     [prtd (part tail LT EQ GT)]                    
                     [LT* (first prtd)]
                     [EQ* (second prtd)]
                     [GT* (third prtd)])
                ;--in--
                (cond
                  ; if x < pivot, add the element to LT
                  [(< head pivot) (list {cons head LT*} EQ* GT*)]
                  ; if x = pivot, add the element to EQ
                  [(= head pivot) (list LT* {cons head EQ*} GT*)]
                  ; if x > pivot, add the element to GT
                  [else (list LT* EQ* {cons head GT*})]
                  )
                ) ) ]
         )
    ;--in--
    (part lst null null null)
    )
  )

第二个版本,更接近您的实施,但使用fold

#lang racket

; partition :: LoN Number -> List-of-LoN
(define (partition2 lst pivot)
  (local([; auxiliary function
          ; part :: LoN LoN LoN LoN -> List-of-LoN
          define (part x LT-EQ-GT)
          (local ([define-values (LT* EQ* GT*) (apply values LT-EQ-GT)])
            ;--in--
            (cond
              ; if x < pivot, add the element to LT
              [(< x pivot) (list {cons x LT*} EQ* GT*)]
              ; if x = pivot, add the element to EQ
              [(= x pivot) (list LT* {cons x EQ*} GT*)]
              ; if x > pivot, add the element to GT
              [else (list LT* EQ* {cons x GT*})]
              )
            ) ]
         )
    ;--in--
    (foldr part '(() () ()) lst)
    )
  )

尝试例如,

(partition2 '(1 2 3 4 4 3 4 5 6) 4) ;; yields '((1 2 3 3) (4 4 4) (5 6)).

请注意,第二个fold - )版本更快(并且更好)。

最后,您的实现在以下行中出错(行号从1开始):

- 第4-7行应该是:

(partition-iter (cdr lst) (cons (car lst) less) same greater)

- 第9-10行应该是:

(partition-iter (cdr lst) less (cons (car lst) same) greater)

- 第12行应该是:

(partition-iter (cdr lst) less same (cons (car lst) greater))

最后,根据您当前的实施情况,您应该在最后一行使用foldlfoldr(或类似内容)。

答案 1 :(得分:0)

这里是您的代码,缩进以便相应的项目在视觉上对齐:

(define (partition lst item)
  (define (partition-iter lst less same greater)
   (cond
      ((null? lst)
                      (list less same greater ))

      ((< (car lst) item)
                      (partition-iter (cdr lst)
                                      (cons (car lst) less)
                                      same
                                      greater))
      ((= (car lst) item)
                      less

                      (cons (car lst) same)

                      (else
                                      (partition-iter (cdr lst)
                                                      (cons (car lst) greater))))))
  (partition-iter lst '() '() '()))

我认为您可以立即看到它出现问题,现在。它是不对称的,所有这些都是出于怪癖,即使parens是平衡的。一个else子句里面另一个cond子句?什么那个??

道德是,不要害怕使用白色空间来更好地看待。有很多很多空白区域。

没有它,Scheme往往看起来像一个难以理解的文字墙,parens或没有parens。和推荐的缩进风格。请问。不。救命。

修复是显而易见的,简单的,简单的:只需以相同的样式完成代码(??)开始编写它。处理其他两种情况,在输入列表中迭代时构建三个临时列表,在三种情况下重复cdr次:

(define (partition lst item)
  (define (partition-iter lst less same greater)
   (cond
      ((null? lst)
                      (list less same greater ))

      ((< (car lst) item)
                      (partition-iter (cdr lst)
                                      (cons (car lst) less)
                                      same
                                      greater ))
      ((= (car lst) item)
                      (partition-iter (cdr lst)
                                      less
                                      (cons (car lst) same)
                                      greater ))

      (else  ; (> (car lst) item)             ; keep it here for documentation!
                      (partition-iter (cdr lst)
                                      less
                                      same
                                      (cons (car lst) greater) )) ))
  (partition-iter lst '() '() '()))

我现在甚至不必将它装入DrRacket以确保它没问题。

对称很漂亮。对称是对的。

BTW,在带有警卫的模式匹配伪代码中,它可以写成

partition lst item = partition-iter lst [] [] []
  where
  partition-iter [] less same greater  =  [less,      same,      greater]
  partition-iter [a, ...lst] less same greater 
     | a < item   =  partition-iter  lst  [a, ...less]   same    greater 
     | a == item  =  partition-iter  lst  less    [a, ...same]   greater
     | else       =  partition-iter  lst  less    same    [a, ...greater]

我觉得这在视觉上更明显。在它与正确的Scheme之间来回走动是一个纯粹的语法转换问题。