stack0114106
stack0114106

Reputation: 8711

scala - mapValues to for comprehension conversion error

I'm trying to convert a chained map() with for-comprehension, but getting error

println("Citi names concatenated by country code")
println("Method1")
orec.groupBy( x => x.ccode ).mapValues( x => x.map( a => a.cityname).mkString("[",",","]")).take(5).foreach(println)
println("Method2")

The below code throws error

var i = 0
for{
  (key,value) <- orec.groupBy( x => x.ccode )
  cities = value.map( a=> a.cityname)
  cities2 = cities.mkString("[",",","]")
  i=i+1
  if(i<5) {
    _ = println(key + "->" + cities2)
  }
} yield ()

Error message:

Error:(49, 10) recursive value i needs type
      i=i+1
Error:(50, 11) value < is not a member of Any
      if(i<5)

How to solve this using immutable way?. Still, I can't figure out how to translate the take(5) in my map() version to for-comprehension.

Upvotes: 0

Views: 466

Answers (2)

som-snytt
som-snytt

Reputation: 39577

You're mistaking "midstream assignment" for assignment to your var i.

The syntax used to require val:

scala> for (i <- List(42) ; val j = i + 1) yield j
                                  ^
       warning: `val` keyword in for comprehension is deprecated: instead, bind the value without `val`
res3: List[Int] = List(43)

scala> val i = i + 1
               ^
       error: recursive value i needs type

It's more usual to keep the take, but improving on the other answer:

scala> for {
     | ((key, value), index) <- orec.groupBy( x => x.ccode ).zipWithIndex
     | cities2 = value.map( a=> a.cityname).mkString("[",",","]")
     | if index < 5
     | } println(key + "->" + cities2)
fr->[paris,lille,bordeaux]
us->[ny]
de->[berlin]
en->[london]
be->[gantt]

or

scala> for {
     | (key, value) <- orec.groupBy(_.ccode)
     | } yield (key, value.map(_.cityname).mkString("[",",","]"))
res4: scala.collection.immutable.Map[String,String] = HashMap(fr -> [paris,lille,bordeaux], us -> [ny], de -> [berlin], en -> [london], be -> [gantt], austria -> [vienna])

scala> .take(5).foreach { case (k,v) => println(s"$k -> $v") }
fr -> [paris,lille,bordeaux]
us -> [ny]
de -> [berlin]
en -> [london]
be -> [gantt]

or

scala> val it = orec.groupBy(_.ccode).mapValues(_.map(_.cityname).mkString("[",",","]")).iterator
                                      ^
       warning: method mapValues in trait MapOps is deprecated (since 2.13.0): Use .view.mapValues(f). A future version will include a strict version of this method (for now, .view.mapValues(f).toMap).
it: Iterator[(String, String)] = <iterator>

scala> for ((k, v) <- it.take(5)) println(s"$k -> $v")
fr -> [paris,lille,bordeaux]
us -> [ny]
de -> [berlin]
en -> [london]
be -> [gantt]

Upvotes: 1

BlueSheepToken
BlueSheepToken

Reputation: 6099

To replace your take(5), you could use an if on the index, to generate the index, you can use zipWithIndex

If you want to increment a var in scala, you need to specify the type of the var. (Here Int)

So this is the code you might be looking for

case class City(ccode: String, cityname: String)
val orec: Seq[City] = Seq(City("fr", "paris"), City("fr", "lille"), City("fr", "bordeaux"), City("en", "london"), City("be", "gantt"), City("de", "berlin"), City("austria", "vienna"), City("us", "ny"))

for (((key, value), index) <- orec.groupBy( x => x.ccode ).zipWithIndex){
  val cities = value.map( a=> a.cityname)
  val cities2 = cities.mkString("[",",","]")
  if (index<5)
    println(key + "->" + cities2)
}

Upvotes: 1

Related Questions