2010-10-21 25 views
6

Sto provando a fare una funzione ricorsiva per ottenere la trasposizione di una lista di liste, n x p a p x n. Ma non sono in grado di farlo. Sono stato in grado di fare una funzione di trasporre una lista di liste 3 x n a un n x 3 uno:trasporre una lista di liste

let rec drop1 list= 
    [(match (List.nth list 0) with [] -> [] | a::b -> b); 
    (match (List.nth list 1) with [] -> [] | a::b -> b); 
    (match (List.nth list 2) with [] -> [] | a::b -> b);] 

let rec transpose list= 
    if List.length (List.nth list 0) == 0 then [] 
    else [(match (List.nth list 0) with [] -> 0 | a::b -> a); 
      (match (List.nth list 1) with [] -> 0 | a::b -> a); 
      (match (List.nth list 2) with [] -> 0 | a::b -> a)] 
     :: transpose (drop1 list) 

Ma io non sono in grado di generalizzare. Sto sicuramente pensando nella direzione sbagliata. È generalizzabile? C'è una soluzione migliore? Per favore aiuto.

risposta

10
let rec transpose list = match list with 
| []    -> [] 
| [] :: xss -> transpose xss 
| (x::xs) :: xss -> 
    (x :: List.map List.hd xss) :: transpose (xs :: List.map List.tl xss) 
+1

+1, Wow! Non ero a conoscenza della funzione List.map. Il manuale dice che non è ricorsivo alla coda. Che effetto può avere se lo uso in un codice più grande? – lalli

+1

@lalli: per gli elenchi molto grandi può causare un overflow dello stack. In tal caso, dovresti usare 'List.rev_map' e poi passare attraverso gli elenchi alla fine e invertirli. Nota comunque che la mia definizione di 'transpose' non è anche ricorsiva della coda (né la tua). – sepp2k

+4

All'inizio non dovresti preoccuparti della ricorsività della coda; cerca di avere un'implementazione semplice e chiara. L'utilizzo di una funzione "trasposizione" su ('un elenco di liste) con elenchi molto grandi è probabilmente una pessima idea. Se si dispone di molti dati, è probabilmente più appropriata un'altra struttura di dati (ad esempio una matrice indicizzata da (int * int), che ha una funzione 'transpose' a tempo costante). – gasche