4

I have a List of tuples, and I'd like to traverse and get the value of each element.

this is the code:

scala> val myTuples = Seq((1, "name1"), (2, "name2"))
myTuples: Seq[(Int, java.lang.String)] = List((1,name1), (2,name2))

scala> myTuples.map{ println _ }
(1,name1)
(2,name2)
res32: Seq[Unit] = List((), ())

So far, so good, but

scala> myTuples.map{ println _._1 }
<console>:1: error: ';' expected but '.' found.
    myTuples.map{ println _._1 }

I also tried with:

scala> myTuples.map{ println(_._1) }
<console>:35: error: missing parameter type for expanded function ((x$1) => x$1._1)
          myTuples.map{ println(_._1) }

scala> myTuples.map{ val (id, name) = _ }
<console>:1: error: unbound placeholder parameter
       myTuples.map{ val (id, name) = _ }

scala> myTuples.map{ x => println x }
<console>:35: error: type mismatch;
 found   : Unit
 required: ?{val x: ?}
Note that implicit conversions are not applicable because they are ambiguous:
 both method any2Ensuring in object Predef of type [A](x: A)Ensuring[A]
 and method any2ArrowAssoc in object Predef of type [A](x: A)ArrowAssoc[A]
 are possible conversion functions from Unit to ?{val x: ?}
              myTuples.map{ x => println x }

Declaring the variable, and using parentheses did the trick, but I'd like to know why the other options didn't work

these worked fine

myTuples.map{ x => println("id: %s, name: %s".format(x._1, x._2)) }

scala> myTuples.map{ x => println("id: %s, name: %s".format(x._1, x._2)) }
id: 1, name: name1
id: 2, name: name2
res21: Seq[Unit] = List((), ())

scala> myTuples.map{ x => val(id, name) = x; println("id: %s, name: %s".format(id, name)) }
id: 1, name: name1
id: 2, name: name2
res22: Seq[Unit] = List((), ())

scala> myTuples.map{ x => println(x._1) }

What happens to me, with my first steps with scala, is that insisting a little bit you get what you want, but you are unsure why the first options you tried didn't work...

opensas
  • 60,462
  • 79
  • 252
  • 386
  • 1
    FWIW, `map` is used when you want to transform the contents of a collection. Since you don't care about the results, `foreach` is the preferred method. – leedm777 Apr 02 '12 at 19:00
  • nice tip, and it also makes much more clearer the intention of the dev – opensas Apr 02 '12 at 19:14

2 Answers2

6

For the options that didn't work:

scala> myTuples.map{ println _._1 }

Short answer: In Scala, you always need to use parens around println's argument. Long answer: Scala only infers parenthesis for infix methods, meaning code of the forms object method argument gets interpreted as object.method(argument). No object is specified, so no parenthesis are inferred. You can see this directly by:

scala> println "Boom!"
<console>:1: error: ';' expected but string literal found.
       println "Boom!"
               ^

Next, myTuples.map{ println(_._1) }. It's not immediately clear to me why this doesn't work, since this should be equivalent to myTuples.map{ x => println(x._1) }, which works. As the answers to this question show, placeholder/partially applied method syntax applies to the smallest possible scope. So equivalent code would be myTuples.map { println(x => x._1) }. Since there's not enough information for scala to infer the type of x, you get a 'missing parameter type' error.

Regarding myTuples.map{ val (id, name) = _ }, placeholders are used in anonymous functions , whereas here you are initializing val's.

Then for myTuples.map{ x => println x }, you're also missing parens.

Finally, the option that worked for you myTuples.map{ x => println("id: %s, name: %s".format(id, name)) }, didn't actually work (look at the data it printed out). My guess if you had already defined id and name in the REPL, and those are the values being printed. Your working solutions work fine now.

My solution for doing what you're trying to do would be:

myTuples foreach {
  case (id, name) => printf("id: %s, name: %s\n", id, name)
}

or

myTuples foreach {
  x => printf("id: %s, name: %s\n", x._1, x._2)
}
Community
  • 1
  • 1
leedm777
  • 23,444
  • 10
  • 58
  • 87
  • Thanks a lot, excellent answer, and you are right, the solution I gave didn't work, this does: myTuples.map{ x => println("id: %s, name: %s".format(x._1, x._2)) } and also this: myTuples.map{ x => val(id, name) = x; println("id: %s, name: %s".format(id, name)) } – opensas Apr 02 '12 at 18:55
  • 2
    `myTuples.map{ println(_._1) }` is equivalent to `myTuples.map{ println(x => x._1) }`. Why would it be anything else? – Daniel C. Sobral Apr 02 '12 at 21:19
  • @DanielC.Sobral "Why would it be anything else?" Apparently because I misunderstood the rules about how _ works. Answer updated. – leedm777 Apr 03 '12 at 13:53
5

I think you want something like:

myTuples map { case(id, name) => println(id+": "+name) }
virtualeyes
  • 11,147
  • 6
  • 56
  • 91