Home > database >  Is there a simple way to transform [[a;b;c];[d;e;f]] into [[a;d];[b;e];[c;f]] in OCaml?
Is there a simple way to transform [[a;b;c];[d;e;f]] into [[a;d];[b;e];[c;f]] in OCaml?

Time:02-28

I'd like to write a function in OCaml, using only recursivity that can transform any list of list that look like: [[a1;...;an];[b1;...bn];...;[z1;...;zn]] into [[a1;b1;...;z1];...;[an;...;zn]] what I've done so far is quite complex, I insert element by element reconstructing a new list every time ... and I'm sure there is a simpler way ... My code so far:

let inserer l e i = 
  let rec aux l e i j = 
    match l with
    | [] -> failwith "erreur position inexistante"
    | t::q when j = i -> 
      if List.length t = 0 then 
        [e]::q 
      else
        let t1 = List.hd t in
        let q1 = List.tl t in
        let l1 = t1::e::q1 in
        l1::q
    | t::q -> t::(aux q e i (j 1)) 
  in
  aux l e i 0

let inserer_liste b m =
  let rec aux b m i = 
    match b with
    | [] -> m
    | t::q -> 
      let tmp = inserer m t i in
      aux q tmp (i 1) 
  in
  aux b m 0

let transform u n =
  let rec aux u m =
    match u with
    | []-> m
    | b::q -> 
      let tmp = inserer_liste b m in
      aux q tmp
  in
  aux u (List.init n (fun _ -> []))

let u = [[1;2;3]; [4;5;6]; [7;8;9]]
let l = transform u 3

CodePudding user response:

I have a feeling that this transformation is way more natural if you transform an array of lists into a lists of arrays. You can transform into a list of lists afterwards.

let rec f a = 
  match a.(0) with
  | [] -> []
  | _ :: _ ->
     let hd = Array.map List.hd a in
     for i = 0 to Array.length a - 1 do
        a.(i) <- List.tl a.(i)
     done ;
     hd :: (f a)

This consumes the input array, which can be solved by shadowing f in the following way :

let f a = f (Array.copy a)

let f_list l = List.map Array.to_list (f (Array.of_list l))

You could also reallocate a new array at each recursive call, but that would be slower, without any upside except maybe a bit nicer code.

f_list is more elegant this way :

let f_list l = 
  l |> Array.of_list |> f |> List.map Array.to_list

There is no error handling in my code : it assumes all list have the same length, but it should be to hard to add it.

CodePudding user response:

Is there a simple way... Not that I know of but that doesn't say much.

Here's something I tried.

let lol =
  [
    [ 1;  2;  3;  4; ];
    [ 5;  6;  7;  8; ];
    [ 9; 10; 11; 12; ];
  ]


let ans =
  List.fold_left
    (
      fun a e ->
        match a with
        | [] -> List.fold_right  (fun e a -> [e]::a) e a
        | _  -> List.fold_right2 (fun b c acc -> (c @ [b])::acc) e a []
    )
    []
    lol

let () =
  List.iter
    (
      fun l ->
        List.iter (fun x -> Printf.printf "%d " x) l; 
        print_newline()
    ) 
    ans
  • Related