2011-11-08 14 views
5

Scrivere una matrice MxN (M righe, N colonne) in un file CSV:Matrix al CSV in Scala

Il mio primo tentativo, usando la mappa, funziona, ma crea N riferimenti al StringBuffer. Scrive inoltre una virgola non necessaria alla fine di ogni riga.

def matrix2csv(matrix:List[List[Double]], filename: String) = { 
    val pw = new PrintWriter(filename) 
    val COMMA = "," 

    matrix.map(row => { 
    val sbuf = new StringBuffer 
    row.map(elt => sbuf.append(elt).append(COMMA)) 
    pw.println(sbuf) 
    }) 
    pw.flush 
    pw.close 
} 

Il mio secondo tentativo, utilizzando ridurre, anche funziona, ma sembra goffo:

def matrix2csv(matrix:List[List[Double]], filename: String) = { 
    val pw = new PrintWriter(filename) 
    val COMMA = "," 

    matrix.map(row => { 
    val sbuf = new StringBuffer 
    val last = row.reduce((a,b)=> { 
     sbuf.append(a).append(COMMA) 
     b 
    }) 
    sbuf.append(last) 
    pw.println(sbuf) 
    }) 
    pw.flush 
    pw.close 
} 

Qualche suggerimento su un approccio più conciso e idiomatica? Grazie.

+0

Come si ottiene il secondo tentativo di compilazione? In 'sbuf.append (b)', non c'è 'b' in scope. –

+0

Grazie Ben. Risolto il problema. –

risposta

8

È possibile ottenere la rappresentazione di stringa facilmente:

val csvString = matrix.map{ _.mkString(", ") }.mkString("\n") 

Poi solo bisogno di scaricare in un file.

Prestare attenzione alle linee di fine (qui "\ n"), variano in base alla piattaforma.

+0

Grazie, è molto conciso e idiomatico. –

5

Idiomaticamente, si sta utilizzando in modo improprio map utilizzandolo per eseguire operazioni di effetto collaterale. Per questo invece dovresti usare foreach.

Questo è quello che potrebbe apparire come se è stato utilizzato un foreach e sostituito il StringBuffer boilerplate con una chiamata al metodo mkString:

def matrix2csv(matrix:List[List[Double]], filename: String) { 
    val pw = new PrintWriter(filename) 
    val COMMA = "," 
    matrix.foreach { row => pw.println(row mkString COMMA) } 
    pw.flush 
    pw.close 
} 

Nota che mkString utilizza un StringBuilder (un non-thread-safe StringBuffer , che va bene qui).