2010-09-03 8 views
5

Per esempio, da un file seguente:In Scala, come trovare un elemein in CSV con una coppia di valori chiave?

 
Name,Surname,E-mail 
John,Smith,[email protected] 
Nancy,Smith,[email protected] 
Jane,Doe,[email protected] 
John,Doe,[email protected] 

come faccio a ottenere l'indirizzo email del John Doe?

Io uso il seguente codice ora, ma si può specificare solo un campo chiave ora:

 

val src = Source.fromFile(file) 
val iter = src.getLines().drop(1).map(_.split(",")) 
var quote = "" 
iter.find(_(1) == "Doe" ) foreach (a => println(a(2))) 
src.close() 
 

Ho provato a scrivere "iter.find (_ (0) == "John" & & _ (1) == "Doe") ", ma ciò solleva un errore che dice che è previsto un solo parametro (il che racchiude la condizione in una coppia extra di parentesi non aiuta).

+0

Se questo è veramente un file CSV, l'uso di StringOps.split (",") è errato e non si occupa dei casi in cui una virgola (,) e/o una virgoletta doppia (") fanno parte di un valore incorporato. Ho appena risolto questo problema nella mia risposta StackOverflow qui: http://stackoverflow.com/a/32488453/501113 – chaotic3quilibrium

risposta

5

Il trattino di sottolineatura come segnaposto per un parametro su una lambda non funziona come si pensa.

a => println(a) 
// is equivalent to 
println(_) 

(a,b) => a + b 
// is equivalent to 
_ + _ 

a => a + a 
// is not equivalent to 
_ + _ 

Cioè, il primo sottolineatura indica il primo parametro e il secondo indica il secondo parametro e così via. Ecco, questo è il motivo dell'errore che stai vedendo: stai usando due caratteri di sottolineatura, ma hai un solo parametro. La correzione è quello di utilizzare la versione esplicita:

iter.find(a=> a(0) == "John" && a(1) == "Doe") 
1

È possibile utilizzare Regex:

scala> def getRegex(v1: String, v2: String) = (v1 + "," + v2 +",(\\S+)").r 
getRegex: (v1: String,v2: String)scala.util.matching.Regex 

scala> val src = """John,Smith,[email protected] 
    | Nancy,Smith,[email protected] 
    | Jane,Doe,[email protected] 
    | John,Doe,[email protected] 
    | """ 
src: java.lang.String = 
John,Smith,[email protected] 
Nancy,Smith,[email protected] 
Jane,Doe,[email protected] 
John,Doe,[email protected] 


scala> val MAIL = getRegex("John","Doe") 
MAIL: scala.util.matching.Regex = John,Doe,(\S+) 

scala> val itr = src.lines 
itr: Iterator[String] = non-empty iterator 

scala> for(MAIL(address) <- itr) println(address) 
[email protected] 

scala> 
+1

E puoi anche utilizzare MAIL.findAllIn (src). – Eastsun

0

Si potrebbe anche fare un pattern match sul risultato di split in un for comprensione.

val firstName = "John" 
val surName = "Doe" 
val emails = for { 
    Array(`firstName`, `surName`, email) <- 
    src.getLines().drop(1) map { _ split ',' } 
} yield { email } 

println(emails.mkString(",")) 

Nota gli apici inversi nel pattern: questo significa che abbiniamo sul valore della firstName invece di introdurre un nuovo nulla corrispondente variabile e shadowing il val firstname.

+0

Utilizzare StringOps.split (",") è errato e non si occupa dei casi in cui una virgola (,) e/o una virgoletta doppia (") fanno parte di un valore incorporato. Ho appena trattato questo nella mia risposta StackOverflow qui: stackoverflow.com/a/32488453/501113 – chaotic3quilibrium

Problemi correlati