(在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) ;;
答案 0 :(得分:4)
在这种情况下
| h1::h2::t -> if h1=h2 then h2::(compress t) else h1::h2::(compress t) ;;
如果h2
与t
的头部相同,您将不会注意到重复。你需要
在(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]