【问题标题】:Finding and removing the last occurrence of a specified element in a list [racket]查找并删除列表中指定元素的最后一次出现 [球拍]
【发布时间】:2013-06-05 00:41:13
【问题描述】:

我已经开始编写一个函数来查找列表中最后一次出现的元素。我的想法是使用search 来计算指定符号的出现次数并返回它。然后我会将计数传递给removeLast,这将删除该元素。然后我会减少removeLast 中的计数以方便基本情况。从我所看到的情况来看,使用set! 通常是不好的做法。有没有更好/更优雅的方式来“记住”符号的最后一次出现。

(define (lastLess lis symbol)
  (define count 0)
   (set! count (search symbol lis count))
  (removeLast symbol lis count)
)

(define (search symbol lis count )
  ( cond ((null? lis) count)
     ( (eq? symbol (car lis)) (+ count (add1 (search symbol (cdr lis) count ))) )
     ( (pair? (car lis))(+ count(+ 0 (search symbol (car lis) count ))))
     ( else (+ count(+ 0 (search symbol (cdr lis) count))))
     )
)

(define (removeLast symbol lis count)
  (cond ((null? lis) '())
    ((eq? count 0) (cdr lis))
    ((eq? symbol (car lis)) ((set! count (sub1 count)) 
                             (cons (car lis)(removeLast symbol (cdr lis) count))
                            )
                            )
    ((pair? (car lis)) (removeLast symbol (car lis) count))
    (else (cons (car lis) (removeLast symbol (cdr lis) count )))
    )
)

((set! count (sub1 count))(cons (car lis)(removeLast symbol (cdr lis) count)))) 运行代码会引发错误:

应用程序:不是程序; 期望一个可以应用于参数的过程 给定:# 论据...: '(e)

编辑:这是一个班级作业,所以多余的reverses 是不可接受的,我必须考虑嵌套列表。

【问题讨论】:

    标签: recursion scheme racket


    【解决方案1】:

    您应该为此使用内置程序。特别注意remove 删除了lis 中等于symbolfirst 元素,因此删除last 元素是一个简单的逆向操作列表:

    (define (lastLess lis symbol)
      (reverse (remove symbol (reverse lis))))
    
    (lastLess '(1 2 3 4 5 1) 1)
    => '(1 2 3 4 5)
    

    上述解决方案根本不需要使用 set!,正如您所怀疑的那样,不推荐使用 - 尽管可以通过改变列表来解决这个问题,但在 Scheme 中首选功能解决方案。

    当然,可以编写一个更有效的解决方案,一个只遍历列表一次的解决方案,但问问你自己:你真的需要这样一个解决方案增加的复杂性吗?高性能有那么重要吗?如果答案是否定的,那么坚持使用更简单、更清晰的解决方案。

    【讨论】:

    • 现在这也会考虑嵌套列表吗?这是课堂作业,我的教授说“不接受多余的反转”。非常感谢您的意见。
    • 这个答案是在编辑之前发布的,不 - 它没有考虑嵌套列表,实际上它正在执行几个(冗余?)反转。编辑后,问题是完全不同(更难)的野兽。抱歉,我现在找不到答案,这里已经过了午夜 :)
    【解决方案2】:

    您遇到的错误来自cond 子句。你有额外的括号 (set!count ...)。

    你的问题是你对 set 的痴迷! 这个:

    (define (lastLess lis symbol)
      (define count 0)
      (set! count (search symbol lis count))
      (removeLast symbol lis count))
    

    本来可以的

    (define (lastLess lis symbol)
      (removeLast symbol lis (search symbol lis 0)))
    

    或者我你想要赋值,这在多个地方使用结果时很好

    (define (lastLess lis symbol)
      (let ((count (search symbol lis 0)))
        (if (< 0 count) ; noe or more occurences
            (removeLast symbol lis count)
            lis)))
    

    您的搜索过程将从列表中的列表开始,而不会以它所在的列表结束。(a b (c d b) a b) 中的每个 a 都将返回 2 而不是 3。+ 可以有任意数量的参数,因此您不需要嵌套它们。试试这个:

    (define (search symbol lis count)
      (cond ((null? lis) count)
         ((eq? symbol (car lis)) (search symbol (cdr lis) (add1 count)))
         ((pair? (car lis)) (search symbol (cdr lis)
                                    (search symbol (car lis) count)))
         (else (search symbol (cdr lis) count))))
    

    注意如何处理对。现在你的 removeLast 不应该跳过它在 count 为零但符号匹配且 count 为 1 时得到的任何东西。

    祝你好运!

    【讨论】:

      【解决方案3】:

      这仍然使用 set,但我认为这是一个更优雅的解决方案,因为 set 在匿名函数的闭包中使用,您将其作为参数作为 foldr 传递。在 if 找到第一个匹配项之后(记住从尾部工作,它会停用自身以作为缺点工作。由于 foldr 从列表的尾部工作,因此不需要额外的遍历。make-remover 是一个功能过程(一个输入将总是映射到相同的输出)但是输出是非功能性的,但这并不是什么大问题,因为你只使用它一次并把它扔掉。(无论如何你都不想要一对一的映射)

      (define (remove-last x L)
       (let ((proc (make-remover x)))
        (foldr proc '() L)))
      
      
      (define (make-remover removee)
       (let ((active? #t))
        (lambda (x y)
         (cond ((not active?) (cons x y))
               ((eq? x removee) (begin (set! active? #f) y))
               (else (cons x y))))))
      

      这不会遍历树(在嵌套列表上工作),但在将过程应用于子列表之前,将 foldr 修改为将在子列表上折叠的 foldr-tree 应该不难。

      【讨论】:

        猜你喜欢
        • 2015-12-12
        • 2014-07-09
        • 1970-01-01
        • 2020-06-09
        • 2018-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-04
        相关资源
        最近更新 更多