删除列表中的重复元素

时间:2014-05-18 01:57:08

标签: list functional-programming scheme lisp

我在编写一些代码时遇到了一些麻烦,但我无法找到错误。编程语言在计划中,问题如下:

只留下不重复的元素。 例如:(a b a a c c) - > (a b)

我写了下面的代码。

    (define x '(a b a a a c c))
    (display x)
    (define z '())
    (define (removeReps y)
    (if (null? y)
      '()
      (if( = (car y) (removeReps (cdr y)))  '() (append z (car y)))))
    (removeReps x)
    (display z)

对于完全披露,这是一项家庭作业,但我无法解决。

谢谢。

5 个答案:

答案 0 :(得分:1)

解决方案不是 简单,你必须跟踪迭代时找到的前一个元素,并且还有一个标志,告诉你前一个元素是否出现过多次。这是我的镜头,假设输入列表是非空的(如果输入列表为空,则处理大小写的情况很简单,留下作为读者的练习):

(define (removeReps lst)
  ; we need some extra parameters, use a named let for iteration
  (let loop ([lst (cdr lst)]  ; list to process, assuming non-empty
             [prev (car lst)] ; pick first as "previous" value
             [first #t])      ; flag: is this the first element in sequence?
    (cond ((null? lst)        ; if we reached the end of the list
           (if first          ; edge case: handle last element
               (list prev)    ; if it was the first in sequence add it
               '()))          ; otherwise skip it and end list
          ; if current element equals previous element
          ((equal? (car lst) prev)
           ; skip it, advance recursion and update flag
           (loop (cdr lst) prev #f))
          ; new element, if previous element had exactly one repetition
          (first
           ; add it to output, advance recursion, update prev and flag
           (cons prev (loop (cdr lst) (car lst) #t)))
          ; new element, if previous element had more than one repetition
          (else
           ; skip it, advance recursion, update prev and flag
           (loop (cdr lst) (car lst) #t)))))

<强>更新

我真的很喜欢@ chris在Haskell中的实现:更高级别并使用现有过程而不是显式递归,它适用于空列表并且转换为Scheme并不太难(它在Scheme中比在Haskell中更冗长,虽然。)这是使用Racket和SRFI-1的span程序的另一种选择,看看@ chris的答案,看看它是如何工作的解释:

(require srfi/1) ; import `span`

(define (group lst)
  (match lst
    ['() '()]
    [(cons x xs)
     (let-values (((ys zs) (span (curry equal? x) xs)))
       (cons (cons x ys) (group zs)))]))

(define (removeReps lst)
  (filter-map (lambda (x) (and (= (length x) 1) (first x)))
              (group lst)))

或者更便携,不使用特定于球拍的程序和特殊表格:

(require srfi/1) ; import `span`

(define (group lst)
  (if (null? lst)
      '()
      (let ((x  (car lst))
            (xs (cdr lst)))
        (let-values (((ys zs) (span (lambda (e) (equal? e x)) xs)))
          (cons (cons x ys)
                (group zs))))))

(define (removeReps lst)
  (map car
       (filter (lambda (x) (= (length x) 1))
               (group lst))))

让我们用一些边缘情况测试程序 - 它可以按照预期的任何上述实现工作:

(removeReps '(a b a a a c c))
=> '(a b)

(removeReps '(x a a x b b x c c x))
=> '(x x x x)

(removeReps '(a a a))
=> '()

(removeReps '(a b b c c))
=> '(a)

(removeReps '(a a b b c c d))
=> '(d)

答案 1 :(得分:1)

另一个似乎处理测试用例的递归解决方案。

;rep is the last repeated elem, input is the input list and first is boolean
(define notrepeatedrec
  (lambda (rep input first)
    (cond ((null? input) (if (eq? first #t) (list rep) '()))
          ((eq? rep (car input)) (notrepeatedrec (car input) (cdr input) #f))
          (else (if (eq? first #t) 
                  (cons rep (notrepeatedrec (car input) (cdr input) #t))
                  (notrepeatedrec (car input) (cdr input) #t))))))

;helper function to start the recursion
(define notrepeated 
  (lambda (lst)
    (notrepeatedrec '() lst #f)))

答案 2 :(得分:0)

另一种可能的解决方案如下

import Data.List

removeDups :: Eq a => [a] -> [a]
removeDups = map head . filter ((== 1) . length) . group

用Haskell编写并使用库函数grouplength(==)filterheadmap

由于以上内容可能不会过于可读,我将逐步完成定义

首先是构成上述定义的各个部分的文字描述

  1. 首先将列表放入包含相等元素的子列表中。
  2. 对于每一个,检查它是否长度恰好为1.如果是,请保留它,否则扔掉它。
  3. 从结果列表中(我们知道每个元素的长度正好为1)我们实际上只需要单个元素,它们对应于单个列表的 head
  4. 现在有些代码。只要它们相等就可以将列表中的元素组合在一起的函数定义如下(抱歉,我使用Haskell语法,因为我不熟悉scheme,但它应该很容易翻译) :

    group :: Eq a -> [a] -> [[a]]
    group []     =  []
    group (x:xs) =  (x:ys) : group zs
      where (ys, zs) = span (== x) xs
    

    其中span是另一个库函数,给定一些谓词p,将其输入列表拆分为元素 all 的初始段,满足p和列表的其余部分。为完整起见,可以定义如下

    span :: (a -> Bool) -> [a] -> ([a], [a])
    span _ [] =  ([], [])
    span p xs@(x:xs')
      | p x =  let (ys, zs) = span p xs' in (x:ys, zs)
      | otherwise =  ([], xs)
    

    mapfilterhead比那些更加标准,我确信它们是方案库的一部分(可能是group

    我想我的主要观点是,一旦将问题分解为小块子问题(使用某些预定义函数)并将结果合并,解决方案就很容易了。

答案 3 :(得分:0)

在Common Lisp中,我将堆栈apis用于列表:

(defun elim-dup (l)
    (if (null l)
        nil
        (progn
            (setf new ())
            (dolist (x l)
                (setq elem (pop l))
                (if (not (member elem new))
                    (push elem new)))
            new)))

如果您更喜欢原始订单,请添加:

(reverse new)

为了避免破坏原始列表,您必须使用第n个元素而不是pop(并维护计数器)。流行更直接但更具破坏性。

答案 4 :(得分:0)

以下几行可能是可以接受的:

;; expr list -> list
;; produce a list where leading elements equal to EXPR have been dropped
(define (drop-in-front elt list)
  (cond [(null? list) list]                            ; empty list, we're done
        [(equal? elt (first list))                     ; first element matches
         (drop-in-front elt (rest list))]              ; drop and repeat
        [#t list]))                                    ; no match, we're done

;; list -> list
;; produce a list where blocks of repeated elements have been dropped
(define (remove-repeated list)
  (cond [(or (null? list)                              ; empty list
             (null? (cdr list)))                       ; or list with one element
         list]                                         ; we're done
        [(equal? (first list)                 
                 (second list))                        ; two matching elements in front
         (remove-repeated                              ; continue with
          (drop-in-front (first list)                  ; list where block in front
                         (rest list)))]                ; has been dropped
        [#t                                            ; first elt different from snd
         (cons (first list)                            ; stick it in front of
               (remove-repeated (rest list)))]))       ; cleaned up rest of list

我真诚地希望你的课程能尽快提供一些风格指南。

如果有机会,请尝试查看Introduction to Systematic Program Design的讲座或查看How to Design Programs