2013-02-20 22 views
7

Vorrei dividere una stringa su spazi che dispone di 4 elementi:Scala diviso stringa da tuple

1 1 4.57 0.83 

e sto cercando di convertire in List [(String, String, Point)] in modo tale che i primi due le divisioni sono i primi due elementi nell'elenco e gli ultimi due sono Punto. Sto facendo il seguente, ma non sembra funzionare:

Source.fromFile(filename).getLines.map(string => { 
      val split = string.split(" ") 
      (split(0), split(1), split(2)) 
     }).map{t => List(t._1, t._2, t._3)}.toIterator 
+1

Se si desidera una tupla, perché stai dicendo di voler convertire in una lista? –

+0

Sono d'accordo, questo dovrebbe probabilmente essere più vicino per convertire la stringa in List() degli elementi –

risposta

8

Si potrebbe utilizzare il pattern matching per estrarre quello che ti serve dalla matrice:

case class Point(pts: Seq[Double]) 
    val lines = List("1 1 4.34 2.34") 

    val coords = lines.collect(_.split("\\s+") match { 
     case Array(s1, s2, points @ _*) => (s1, s2, Point(points.map(_.toDouble))) 
    }) 
+1

Questo non viene compilato per me, ho aggiunto un'altra risposta simile che compila: non ho potuto ottenere che il codice si visualizzasse correttamente nei commenti. Sarei curioso di vedere come potrebbe essere raccolto se qualcuno lo sa. –

+0

dall'API di 'collect' *" Crea una nuova raccolta applicando una funzione parziale a tutti gli elementi di questo elenco su cui è definita la funzione. "*. È proprio come 'map' ma lascia solo gli elementi nel dominio della funzione parziale –

1

Lei non è convertire il terzo e il quarto gettoni in un Point, né siete convertendo le linee in un List. Inoltre, non stai rendendo ogni elemento come Tuple3, ma come List.

Quanto segue dovrebbe essere più in linea con quello che stai cercando.

case class Point(x: Double, y: Double) // Simple point class 
Source.fromFile(filename).getLines.map(line => { 
    val tokens = line.split("""\s+""") // Use a regex to avoid empty tokens 
    (tokens(0), tokens(1), Point(tokens(2).toDouble, tokens(3).toDouble)) 
}).toList // Convert from an Iterator to List 
+0

PS: non l'ho provato. – cheeken

+0

La classe My Point impiega (IndexedSeq [Double]), quindi come faccio a ottenere Seq indicizzato da tupla? –

13

ne dite di questo:

scala> case class Point(x: Double, y: Double) 
defined class Point 

scala> s43.split("\\s+") match { case Array(i, j, x, y) => (i.toInt, j.toInt, Point(x.toDouble, y.toDouble)) } 
res00: (Int, Int, Point) = (1,1,Point(4.57,0.83)) 
+0

Semplice e chiaro. Si potrebbe voler aggiungere un caso per la gestione degli errori di input. –

-1

Ci sono modi per convertire una tupla di elenco o Seq , One way is

scala> (1,2,3).productIterator.toList 
res12: List[Any] = List(1, 2, 3) 

Bu t come si può vedere che il tipo di ritorno è Qualsiasi e non un INTERO

per la conversione in diversi tipi di utilizzare HList di https://github.com/milessabin/shapeless

1
case class Point(pts: Seq[Double]) 
val lines = "1 1 4.34 2.34" 

val splitLines = lines.split("\\s+") match { 
    case Array(s1, s2, points @ _*) => (s1, s2, Point(points.map(_.toDouble))) 
} 

E per i curiosi, la @ nel modello matching combina una variabile con il pattern, quindi points @ _* sta vincolando i punti variabili al pattern * _ E * _ corrisponde al resto dell'array, quindi i punti finiscono per essere un Seq [String].

+0

Hm .. Ricevo scala.MatchError: [Ljava.lang.String; @ 7bfacd5d (di classe [Ljava.lang.String;) Cosa faccio di sbagliato? – Sergey