【问题标题】:Counts of repeated elements in a list列表中重复元素的计数
【发布时间】:2014-04-19 05:35:47
【问题描述】:

该程序获取元素重复的列表,例如L = (a a a b b b c c c d),并输出项目列表和重复次数,例如((a 3)(b 3)(c 3) d)

(define counter 0)
(define (compress liste)
(if (or (null? liste) (null? (cdr liste)))
   liste
(let ((compressed-cdr (compress (cdr liste)))) 
   (if (equal? (car liste) (car compressed-cdr))
   ((+ counter 1) compressed-cdr)
  ((cons (car liste) counter) (= counter 0) (compressed-cdr))))
                       ))

但是,我收到此错误:

错误:应用程序:不是程序;期望一个可以应用于参数的过程
给定:1 个参数 ...

错误在第二个 if 条件的真谓词处。

【问题讨论】:

    标签: list recursion scheme let run-length-encoding


    【解决方案1】:

    为简单起见,使用“head-sentinel 技巧”以自上而下的方式构建结果列表:

    (define (rle lst)
      (if (null? lst) 
       '()
       (let ((res (list 1)))        ; head sentinel
          (let loop ((p   res)      ; result's last cons cell  
                     (elt (car lst))
                     (cnt 1) 
                     (lst (cdr lst)))
             (if (and (not (null? lst))
                      (equal? elt (car lst)))
                (loop p elt (+ cnt 1) (cdr lst))
                (begin
                   (set-cdr! p (list (if (= 1 cnt) elt (list elt cnt))))
                   (if (null? lst)
                      (cdr res)     ; skip the head in result, on return
                      (loop (cdr p) (car lst) 1 (cdr lst)))))))))
    

    正如@uselpa 所解释的,这称为游程编码;为了结果的一致性,我建议对非重复元素使用(x 1) 表示。

    而错误"Error: application: not a procedure; expected a procedure",正如其他人所说,意味着系统期望找到一个过程但发现了别的东西,所以不能应用它。 Scheme 希望找到一个过程作为列表中的第一个形式:(proc args ...),并尝试将其应用于参数。但是在你的代码中它不是一个过程,而是一些其他类型的数据。


    如果你的 Scheme 有左折叠,或者reduce,你可以运行两次 - 首先收集统一的结果,然后在反转时应用你的特殊格式(左折叠的结果通常以相反的顺序构建):

    (define (fold f init lst)            ; if fold is not defined,
       (reduce f init (cons init lst)))  ;   define it in terms of reduce
    
    (define (rle lst)
       (fold (lambda (x acc)             ; NB! MIT-Scheme: (acc x)
                 (if (= 1 (cadr x))  (cons (car x) acc)  (cons x acc)))
             '()
          (fold (lambda (x acc)          ; NB! MIT-Scheme: (acc x)
                    (if (or (null? acc) (not (equal? (caar acc) x)))
                       (cons (list x 1) acc)
                       (cons (list x (+ (cadar acc) 1)) (cdr acc))))
                '() 
                lst)))
    

    【讨论】:

    • 感谢详细解答,我无法跟踪计数器变量cnt,(cnt 1) 是否将其设置为1?
    • 是和不是。 :) 它将其初始值指定为 1(即本身不是 sets 它)。
    【解决方案2】:

    正如错误消息所说,问题位于“第二个 if 条件的真谓词”:

    ((+ counter 1) compressed-cdr)
    

    在这种情况下,(+ counter 1) 的计算结果应该是一个过程,但它的计算结果是一个数字。我认为问题在于您不知道如何增加计数器。

    你的假谓词也有同样的问题:

    ((cons (car liste) counter) (= counter 0) (compressed-cdr))))))
    

    (cons (car liste) counter) 产生一个列表而不是一个过程。

    我认为我们无法真正使用此代码。我建议查看R Sahu's answer,它很接近。或者,我可以向您展示一个 tail-recursive 版本,您也可以看看。顺便说一句,这称为 run-length encoding,因此我将我的程序称为 rle:

    (define (rle lst)
    
      (define (newres prv cnt res)
        (case cnt
          ((0)  res) 
          ((1)  (cons prv res)) 
          (else (cons (list prv cnt) res))))
    
      (let loop ((lst lst) (prv null) (cnt 0) (res null))
        (if (null? lst)
            (if (zero? cnt)
                (reverse res)
                (loop null null 0 (newres prv cnt res)))
            (let ((c (car lst)))
              (if (eq? c prv)
                  (loop (cdr lst) prv (add1 cnt) res)
                  (loop (cdr lst) c 1 (newres prv cnt res)))))))
    

    【讨论】:

      【解决方案3】:

      我很难找出问题出在您的代码中。我尝试了以下似乎可行的方法。

      (define (compress liste)
      
        (define (helper in prev out)
           (if (null? in)
              (list (list (car out) (length out)))
              (if (equal? prev (car in))
                (helper (cdr in) prev (append out (list (car in))))
                (cons (list (car out) (length out)) (compress in)))))
      
      
          (if (null? liste)
            '()
            (helper (cdr liste) (car liste) (list (car liste))))
            )
      

      它使用helper 收集匹配项的输出。当它发现不匹配时,它会调用 main 函数来处理列表的其余部分。 helper 只是将其结果添加到从 main 函数获得的结果之前。

      稍微改进的版本:

      (define (compress liste)
      
        (define (helper in prev out)
           (if (null? in)
              (list (list prev out))
              (if (equal? prev (car in))
                (helper (cdr in) prev (+ 1 out))
                (cons (list prev out) (compress in)))))
      
          (if (null? liste)
            '()
            (helper (cdr liste) (car liste) 1))
            )
      

      这是尾递归版本:

      (define (compress liste)
      
        (define (helper-1 in out)
          (if (null? in)
            '()
            (helper-2 (cdr in) (car in) 1 out)))
      
        (define (helper-2 in prev count out)
          (if (null? in)
            (append out (list (list prev count)))
            (if (equal? prev (car in))
              (helper-2 (cdr in) prev (+ 1 count) out)
              (helper-1 in (append out (list (list prev count)))))))
      
        (helper-1 liste '()))
      

      【讨论】:

        猜你喜欢
        • 2012-10-05
        • 2023-03-11
        • 2011-05-07
        • 2017-11-09
        • 2020-06-04
        • 1970-01-01
        • 2019-08-01
        • 2020-06-27
        • 2019-04-12
        相关资源
        最近更新 更多