Создайте раздел списка на три части в схеме

Я пытаюсь найти способ разделить список на три части. Я использовал вспомогательную функцию, и параметры должны быть следующими: она оценивается как список из трех списков, содержащих 1) элементы в списке меньше, чем точка поворота, 2) элементы в списке, равные точке поворота, и 3) элементы в списке больше, чем точка поворота.

(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 должно работать, но после этого я застрял. Любая помощь приветствуется


person ajs    schedule 02.04.2018    source источник
comment
Термин (= ...) и термин else должны выглядеть так же, как термин (< ...), с той разницей, что вы указываете в другом месте. Прямо сейчас вы этого не делаете, и ваш else является следствием срока (= ...).   -  person Sylwester    schedule 03.04.2018


Ответы (2)


Текущая вспомогательная функция 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-) версия быстрее (и лучше IMO).

Наконец, в вашей реализации есть ошибки в следующих строках (нумерация строк начинается с 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))

Наконец, в вашей текущей реализации вы должны использовать foldl или foldr (или что-то в этом роде) в последней строке.

person AlQuemist    schedule 03.04.2018

Вот ваш код с отступом, чтобы соответствующие элементы были визуально выровнены:

(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 внутри другого предложения cond? Что это это??

Мораль такова: не бойтесь использовать пустое пространство, чтобы лучше видеть. Много-много пустого пространства.

Без него Scheme имеет тенденцию выглядеть как непроницаемая стена слов, скобок или без скобок. И рекомендуемый стиль отступа. Делает. Нет. Помощь.

Исправление очевидное, минимальное и простое: просто завершите код в том же стиле, который вы (??) начали его писать. Обработайте два других случая, построив три промежуточных списка, проходя по входному списку, повторяя 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, чтобы убедиться, что все в порядке.

Симметрия красивая. Симметрия правильная.


Кстати, в псевдокоде сопоставления с образцом с охранниками это можно было бы записать как

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]

что, я думаю, гораздо более наглядно. Переход туда и обратно между ним и правильной схемой — это вопрос чисто синтаксических преобразований.

person Will Ness    schedule 03.04.2018