【问题标题】:Print adjacent duplicates of a list (scheme)打印列表的相邻副本(方案)
【发布时间】:2015-12-11 09:27:30
【问题描述】:

我正在尝试创建一个返回列表相邻副本的函数,例如 (dups '(1 2 1 1 1 4 4) 应该返回列表 (1 4)。

这是我目前想出的代码:

(define (dups lst)
    (if (equal? (car lst)(car(cdr lst)))
        (cons(cdr lst) '())
        (dups(cdr lst))))

这个函数不会返回所有相邻的重复,它只返回第一个相邻的重复! 如何修复它以使其返回列表的所有相邻副本?

谢谢。

【问题讨论】:

  • 这应该对(1 1 4 4 1 1) 做什么? (1 1 1 1 1)?
  • (1 1 4 4 1 1) > 应该返回 (1 4 1)
  • (1 1 1 1 1) > 应该返回 (1)

标签: scheme lisp


【解决方案1】:

一旦您的代码找到重复项,它就会停止处理列表的其余部分:当if 测试为真时,它会产生(cons (cdr lst) '())。无论是否找到重复项,它仍应调用dups 来处理列表的其余部分。

另外:如果你的列表没有重复,它会遇到麻烦。

这是一个比其他人发布的更简单的解决方案:

(define (dups lst)
    (if (< (length lst) 2)
        ; No room for duplicates
        '()
        ; Check for duplicate at start
        (if (equal? (car lst) (cadr lst))
            ; Starts w/ a duplicate
            (if (or (null? (cddr lst)) ; end of list
                    (not (equal? (car lst) (caddr lst)))) ; non-matching symbol next
                ; End of run of duplicates; add to front of what we find next
                (cons (car lst) (dups (cdr lst)))
                ; Othersise keep looking
                (dups (cdr lst)))
            ; No duplicate at start; keep looking
            (dups (cdr lst)))))

【讨论】:

  • 是的,我看到了问题!但为什么它停止了?为什么它不一直叫dups?是因为我使用了“if 语句”吗?
  • 如果第一个元素不是重复的,它不应该出现在结果中!问题是“只保留重复元素的一份副本”,例如: (dups '(2 3 3 4 4 4 5)) -> (3 4)
  • 谢谢,这看起来很简单!
  • 不错的解决方案。不过,出于性能原因,我总是尽量避免使用length
  • @uselpa:我是为了清楚起见;可以将(&lt; (length last) 2) 替换为(or (null? lst) (null? (cdr lst)))
【解决方案2】:

基本上,这归结为只保留与前一个相同但与下一个不同的元素。

这是一个使用命名 let 的示例实现。

(define (adj-dups lst)
      (let loop ((lst (reverse (cons (gensym) lst)))
                 (e-2 (gensym))
                 (e-1 (gensym))
                 (acc '()))
        (if (null? lst) 
            acc
            (let ((e-0 (car lst)))
              (loop (cdr lst)
                    e-1
                    e-0
                    (if (and (eqv? e-2 e-1) (not (eqv? e-1 e-0)))
                        (cons e-1 acc)
                        acc))))))

(gensym) 在这里派上用场,因为它是一种方便的方法,可以使用与其他所有内容不同的东西来初始化工作变量,并用需要添加的虚拟元素填充初始列表,这样我们就不会错过最后一个元素。 测试:

> (adj-dups '())
'()
> (adj-dups '(1 1 4 4 1 1))
'(1 4 1)
> (adj-dups '(1 1 1 1 1))
'(1)
> (adj-dups '(1 2 1 1 1 4 4))
'(1 4)
> (adj-dups '(2 3 3 4 4 4 5))
'(3 4)

【讨论】:

    【解决方案3】:

    我能想到的最直接的解决方法是使用一个内部过程,该过程带有一个额外的变量来跟踪前一个元素是什么,以及一个布尔值来跟踪元素是否重复。然后,您可以在辅助函数和主函数之间进行相互递归,以一次构建一个重复元素的答案。

    (define (dups lst)
       (define (dups-helper x repeat? L)
          (cond ((null? L)
                 (if repeat? 
                     (list x)
                     '()))
                ((equal? x (car L))
                 (dups-helper x #t (cdr L)))
                (else 
                 (if repeat?
                     (cons x (dups L))
                     (dups L)))))
      (if (null? lst)
          '()
          (dups-helper (car lst) #f (cdr lst))))
    
    (dups (list 1 1 4 4 5 6 3 3 1))
     ;Value 43: (1 4 3)
    

    【讨论】:

    • 我认为相互递归正在对相互递归的数据进行操作。我试图从这个程序实现中找到数据的定义。我觉得这个解决方案很有趣。
    猜你喜欢
    • 1970-01-01
    • 2012-11-13
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多