如何消除连续重复的列表元素?

时间:2011-12-24 05:51:12

标签: list ocaml

(在Ocaml中)

此解决方案有效

let compress l =
let rec compress_2 l e =
    match l with
        | [] -> [e]
        | h::t -> if (h=e)
                    then (compress_2 t e)
                    else e::(compress_2 t)
in
    match l with
        | [] -> []
        | h::t -> compress_2 t h;;

但为什么这个解决方案不起作用?

let rec compress (l: 'a list) : 'a list =
match l with
    | [] -> []
    | h::[] -> [h]
    | h1::h2::t -> if h1=h2 then h2::(compress t) else h1::h2::(compress t) ;;

2 个答案:

答案 0 :(得分:4)

在这种情况下

| h1::h2::t -> if h1=h2 then h2::(compress t) else h1::h2::(compress t) ;;

如果h2t的头部相同,您将不会注意到重复。你需要 在(h2 :: t)的递归调用中传递compress

我已多次编写此函数(可能是标准列表库的候选者)。这是我通常写的方式(避免额外的利弊):

let rec compress l =
    match l with
    | [] -> []
    | [_] -> l
    | h1 :: ((h2 :: _) as tail) ->
        if h1 = h2 then compress tail else h1 :: compress tail

这不是尾递归,因此它消耗了线性的堆栈空间。如果你知道你的名单往往很短,那就没问题了。

答案 1 :(得分:1)

ExtLib(以及电池)确实有这个功能 - 即使有一个额外的参数传递你自己的相等功能: http://nit.gforge.inria.fr/extlib/ExtList.List.html#VALunique

如果你想自己动手,试试这个:

let compress eq ls =
   (* acc: accumulator; x: the optional comparison value; xs: the not-unique list *)
   let rec remdup acc x xs =
    match (x, xs) with
    | (_, []) -> acc
    | (None, y::ys) -> remdup (y::acc) (Some y) ys
    | (Some z, y::ys) -> if eq z y then remdup acc x ys else remdup (y::acc) (Some y) ys
   in
   (* need to reverse the final list as we appended in front of the accumulator *)
   List.rev (remdup [] None ls)

然后只是

  

let unique = compress(=)[1; 1; 1; 2; 3; 3; 4; 5; 6; 6; 7; 8; 9; 9; 9]