0

My goal is to to map every word in a text (Index, line) to a list containing the indices of every line the word occurs in. I managed to write a function that returns a list of all words assigned to a index.

The following function should do the rest (map a list of indices to every word):

def mapIndicesToWords(l:List[(Int,String)]):Map[String,List[Int]] = ???

If I do this:

l.groupBy(x => x._2)

it returns a Map[String, List[(Int,String)]. Now I just want to change the value to type List[Int]. I thought of using .mapValues(...) and fold the list somehow, but I'm new to scala and don't know the correct approach for this.

So how do I convert the list?

Melkor
  • 243
  • 2
  • 14

2 Answers2

1

Also you can use foldLeft, you need just specify accumulator (in your case Map[String, List[Int]]), which will be returned as a result, and write some logic inside. Here is my implementation.

def mapIndicesToWords(l:List[(Int,String)]): Map[String,List[Int]] =
  l.foldLeft(Map[String, List[Int]]())((map, entry) =>
    map.get(entry._2) match {
      case Some(list) => map + (entry._2 -> (entry._1 :: list))
      case None => map + (entry._2 -> List(entry._1))
    }
  )

But with foldLeft, elements of list will be in reversed order, so you can use foldRight. Just change foldLeft to foldRight and swap input parameters, (map, entry) to (entry, map).

And be careful, foldRight works 2 times slower. It is implemented using method reverse list and foldLeft.

Duelist
  • 1,562
  • 1
  • 9
  • 24
  • According to the [source code](https://github.com/scala/scala/blob/v2.12.6/src/library/scala/collection/TraversableOnce.scala#L1), `foldRight` is implemented via `foldLeft` and neither one of them are recursive (tail or otherwise). – jwvh Jun 03 '18 at 14:04
  • I know that all methods are implemented in imperative style, but I didn't know that foldRight is implemented as reverse.foldLeft. So, thank you for clarifying! – Duelist Jun 03 '18 at 14:12
0
scala> val myMap: Map[String,List[(Int, String)]]  = Map("a" -> List((1,"line1"), (2, "line")))
myMap: Map[String,List[(Int, String)]] = Map(a -> List((1,line1), (2,line)))

scala> myMap.mapValues(lst => lst.map(pair => pair._1))
res0: scala.collection.immutable.Map[String,List[Int]] = Map(a -> List(1, 2))
pedrorijo91
  • 7,635
  • 9
  • 44
  • 82