5

For example, from a following file:

Name,Surname,E-mail
John,Smith,john.smith@hotmail.com
Nancy,Smith,nancy.smith@gmail.com
Jane,Doe,jane.doe@aol.com
John,Doe,john.doe@yahoo.com

how do I get e-mail address of John Doe?

I use the following code now, but can specify only one key field now:


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()

I've tried writing "iter.find( _(0) == "John" && _(1) == "Doe" )", but this raises an error saying that only one parameter is expected (enclosing the condition into extra pair of parentheses does not help).

Ivan
  • 63,011
  • 101
  • 250
  • 382
  • If this is really a CSV file, using StringOps.split(",") is erroneous and doesn't deal with the cases where either a comma (,) and/or a double quote (") are part of an embedded value. I just addressed this in my StackOverflow answer here: http://stackoverflow.com/a/32488453/501113 – chaotic3quilibrium Sep 09 '15 at 20:39

3 Answers3

5

The underscore as a placeholder for a parameter to a lambda doesn't work the way that you think.

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

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

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

That is, the first underscore means the first parameter and the second one means the second parameter and so on. So that's the reason for the error that you're seeing -- you're using two underscores but have only one parameter. The fix is to use the explicit version:

iter.find( a=> a(0) == "John" && a(1) == "Doe" )
denis phillips
  • 12,550
  • 5
  • 33
  • 47
1

You can use 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,john.smith@hotmail.com
     | Nancy,Smith,nancy.smith@gmail.com
     | Jane,Doe,jane.doe@aol.com
     | John,Doe,john.doe@yahoo.com
     | """
src: java.lang.String =
John,Smith,john.smith@hotmail.com
Nancy,Smith,nancy.smith@gmail.com
Jane,Doe,jane.doe@aol.com
John,Doe,john.doe@yahoo.com


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)
john.doe@yahoo.com

scala>
Eastsun
  • 18,526
  • 6
  • 57
  • 81
0

You could also do a pattern match on the result of split in a for comprehension.

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

println(emails.mkString(","))

Note the backticks in the pattern: this means we match on the value of firstName instead of introducing a new variable matching anything and shadowing the val firstname.

mkneissl
  • 4,902
  • 2
  • 26
  • 28
  • Using StringOps.split(",") is erroneous and doesn't deal with the cases where either a comma (,) and/or a double quote (") are part of an embedded value. I just addressed this in my StackOverflow answer here: stackoverflow.com/a/32488453/501113 – chaotic3quilibrium Sep 09 '15 at 20:40