【问题标题】:eliminate the last occurrence of an element in a list in racket消除球拍列表中最后一次出现的元素
【发布时间】:2015-12-12 08:29:25
【问题描述】:

我只是想知道,我可以在球拍中创建一个函数来消除列表中最后一次出现的元素吗,例如,

>(last-without   '(a b  a  (c e) d)    'e)  =  (a b a (c) d)
>(last-without   '(p q  p (r p) q e p r)   'p) = (p q  p (r p) q e r)

这也可以通过定义嵌套列表的成员资格测试来完成,方法是概括可用于设置 last-without 递归调用的内置成员,而不使用冗余反向。

【问题讨论】:

    标签: list recursion scheme racket


    【解决方案1】:
    (define (last-without list el)
      (define (remove-last-rec lst)
        (cond ((null? lst) '())
              ((equal? (car lst) el) (cdr lst))
              ; Corner case below, if car is a list, we also have to check it for occurences of el
              ((list? (car lst)) (let* ((nested (car lst))
                                        (rest (cdr lst))
                                        (nested-res (last-without nested el)))
                                   (if (equal? nested nested-res)
                                       (cons nested-res (remove-last-rec rest)); el did not occur in nested list
                                       (cons nested-res rest)))) ; We did removed it, not remove it from cdr anymore, instead just cons the unchanged cdr.
              (else (cons (car lst) (remove-last-rec (cdr lst))))))
    
      (reverse ; Reverse filtered list back to original order
       (remove-last-rec 
        (reverse list))))
    

    您会注意到(car lst) 是一个列表的极端情况。 如果它是一个列表,我们必须检查它是否出现el

    重要是我们在该列表中调用last-without 而不是remove-last-rec。这是因为嵌套列表没有被初始调用中的原始reverse 反转,(reverse (remove-last-rec (reverse list)))

    如果您调用remove-last-rec,结果中嵌套列表的顺序将是错误的。我建议您自己尝试(错误地调用remove-last-rec),尝试提出您认为可能会失败的列表非常有启发性。

    如果找不到,试试这个。 它不会输出你所期望的。

    (last-without '(a (b c a c) b) 'c)
    

    EDIT :极端情况需要显式测试来检查(last-without nested el) 是否返回相同的嵌套列表。如果没有,则嵌套列表nested中最后出现的el被过滤掉了,我们不需要再过滤掉rest中最后出现的el了。

    【讨论】:

    • 你的解决方案在(last-without '(p (p p)) 'p)这样的情况下,返回((p))
    【解决方案2】:

    这里有一个解决方案:

    (define (last-without lst el)
      (define (aux lst)  ; returns two values: removed and result
        (if (null? lst)
            (values #f '())
            (let-values (((removed result) (aux (cdr lst))))
                    (if removed
                        (values removed (cons (car lst) result))
                        (cond ((equal? (car lst) el) (values #t result))
                              ((list? (car lst))
                               (let-values (((removed-from-car result-of-car) (aux (car lst))))
                                 (values removed-from-car (cons result-of-car result))))
                              (else (values #f (cons (car lst) result))))))))
      (let-values (((removed result) (aux lst)))
        result))
    

    辅助函数执行删除元素并返回两个值:一个布尔值,如果元素已被删除,则为#t,以及结果列表。因此,在检查列表不为空之后,它将自身应用于列表的其余部分,并返回两个值。如果removed#t,则无需执行任何其他操作并且重新构建列表。否则函数必须仍然删除元素,所以它检查它是否等于lst的第一个元素并在这种情况下删除它,否则,如果第一个元素是一个列表,则调用自己就可以了。

    最后请注意,标题在某种程度上具有误导性:该函数不会从列表中删除最后一个 el 元素,而是删除树中最右边的 el 元素。

    【讨论】:

      【解决方案3】:

      试试

      (define (remove-last xs)
        (reverse (remove-first (reverse xs) x)))
      

      (remove-first xs x) 将删除 xs 中第一次出现的x

      【讨论】:

      • 这不适用于嵌套列表,是吗?在remove-first 过程中遇到嵌套列表时,不会反转它(因此删除嵌套列表中的第一个出现而不是最后一个)。
      • 仅当remove-first 在下降到子树时调用remove-last
      • 但目的是让 OP 自己写 remove-first
      猜你喜欢
      • 1970-01-01
      • 2014-07-09
      • 1970-01-01
      • 1970-01-01
      • 2021-02-25
      • 2020-06-09
      • 2015-11-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多