ocaml

Removing duplicates from a list while maintaining order from the right


I just read this thread and find it interesting.

I implement the remove from the left function in a few minutes:

(*
 * remove duplicate from left:
 * 1 2 1 3 2 4 5 -> 1 2 3 4 5
 * *)
let rem_from_left lst =
  let rec is_member n mlst =
    match mlst with
    | [] -> false
    | h::tl ->
        begin
          if h=n then true
          else is_member n tl
        end
  in
  let rec loop lbuf rbuf =
    match rbuf with
    | [] -> lbuf
    | h::tl ->
        begin
          if is_member h lbuf then loop lbuf tl
          else loop (h::lbuf) rbuf
        end
  in
  List.rev (loop [] lst)

I know I could implement the is_member by Map or hashtable to make it faster, but in this moment that's not my concern.

In the case of implementing the remove from the right, I can implement it by List.rev:

(*
 * remove duplicate from right:
 * 1 2 1 3 2 4 5 -> 1 3 2 4 5
 * *)
let rem_from_right lst =
  List.rev (rem_from_left (List.rev lst))

I'm wondering if we can implement it in another way?


Solution

  • Instead of accumulating the values on the way recursing to the end, you can collect the values on the way back up:

    let rem_from_right lst =
      let rec is_member n mlst =
        match mlst with
        | [] -> false
        | h::tl ->
            begin
              if h=n then true
              else is_member n tl
            end
      in
      let rec loop lbuf =
        match lbuf with
        | [] -> []
        | h::tl ->
            begin
            let rbuf = loop tl
            in
              if is_member h rbuf then rbuf
              else h::rbuf
            end
      in
      loop lst