2014-01-22 92 views
1

如果我们假设从0计数元素,如何反转列表的子列表。我希望解决方案是“手动编码”的。这个任务我遇到了很大的问题。Ocaml中的列表反转

例如:

Function([[1;2;3] ; [2;3] ; [1;2;3] ; [5;6;7]]) 

回报:

([[3;2;1] ; [2;3] ; [3;2;1] ; [5;6;7]]) 

我已经创建了一个反向单列表的功能:

let rev = 
    let rec rev_append acc l = 
    match l with 
     [] -> acc 
    | h::t -> rev_append (h::acc) t in 
    fun l -> rev_append [] l;; 

但现在我卡住了。

回答

1
let rev_list l = 
    let rec rev_acc acc = function 
    | [] -> acc 
    | hd::tl -> rev_acc (hd::acc) tl 
    in 
    rev_acc [] l 

let rev_even l = 
    let rec rev i acc = function 
    | [] -> rev_list acc 
    | hd::tl -> 
     if i mod 2 = 0 then rev (i+1) ((rev_list hd)::acc) tl 
     else rev (i+1) (hd::acc) tl 
    in 
    rev 0 [] l 

注意,他们都是尾递归

编辑

有人建议的Noran:

尾递归是函数式编程和OCaml中非常重要。请记住。

+0

可以使用相互递归函数来跳过列表中的其他每个元素,而不是使用'mod'。 – nlucaroni

+1

@nlucaroni是的,你是对的。考虑到Noran是一个新的学习者,我写这种方式只是为了根据问题规范更直接地展示过程。 –

+0

是的,非常感谢。 Greate工作:) –

3
let rec todo l = let rec aux r = function 
     | [] -> [] 
     | h::t -> (if r then h else rev h)::(aux (not r) t) 
in aux true l;; 
+0

它不工作的罚款。它反向列表1,3,5 ...而不是0,2,4 ... –

+0

但是没关系,我也可以利用它。非常感谢! –

1

为了好玩,我已经做了这样的东西,

let rev_at_even_idx list = 
    let s0, s1 = ([], 0), [] in 
    let aux0 (a, i) x = 
    (x, i mod 2) :: a, succ i 
    in 
    let aux1 a = function 
    | l, 0 -> List.rev l :: a 
    | l, _ -> l :: a 
    in 
    List.fold_left aux1 s1 
    @@ fst @@ 
    List.fold_left aux0 s0 list 
;; 

rev_at_even_idx [[1;2;3] ; [2;3] ; [1;2;3] ; [5;6;7]];; 
- : int list list = [[3; 2; 1]; [2; 3]; [3; 2; 1]; [5; 6; 7]]