qartal
qartal

Reputation: 2064

Converting Function1 to Map in Scala

I am trying to compose two maps and get a composed map in Scala. I am doing the following:

val m1=Map(1->'A',2->'C',3->'Z')
val m2=Map('A' -> "Andy", 'Z'->"Zee",'D'->"David")

val m3=m2.compose(m1)

Now m3 is m1;m2, but its type is Function1.

Question: How can I convert Function1 to Map?

ps. Here, instead of m2.compose(m1), it is suggested to use val m3 = m1 andThen m2. Anyways, the result is of type Function1.

Upvotes: 1

Views: 202

Answers (3)

AmigoNico
AmigoNico

Reputation: 6852

Why composing two Maps gives you a Function1

A Map offers the semantics of a Function1 and then some. When you compose two Map functions, you get a new Function1 because compose is an operation on functions.

So you should not expect to get a Map by composing two Maps -- you are just composing the function aspects of the Maps, not the Maps themselves.

How to get a composed Map

To actually compose two Maps into another Map, you can use mapValues, but be careful. If you do it like this:

val m3 = m1 mapValues m2

you will silently get a view (see this bug) rather than a simple map, so as you do lookups in m3 it will really do lookups in m1 and then in m2. For large Maps and few lookups, that's a win because you didn't process a lot of entries you didn't need to. But if you do lots of lookups, this can cause a serious performance problem.

To really make a new single Map data structure that represents the composition of m1 and m2 you need to do something like

val m3 = (m1 mapValues m2).view.force

That is kind of unfortunate. In a perfect world m1 mapValues m2 would give you the new single composed Map -- and very quickly, by creating a new data structure with shape identical to m1 but with values run through m2 -- and (m1 mapValues m2).view would give you the view (and the type would reflect that).

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170713

You can also do

val m3: Map[Int, String] = m1.mapValues(m2)

There is a caveat that despite the return type this will recalculate m2(m1(x)) on every access to m3(x), just like m2.compose(m1).

since I updated the title of the question, the answer does not now directly address the question subject. I will wait to see if somebody possibly provides a direct answer (that is, how to convert Function1 to map).

def funToMap[A, B](f: A => B): Map[A, B] = Map.empty[A, B].withDefault(f)

Upvotes: 1

Dmitry  Meshkov
Dmitry Meshkov

Reputation: 931

What do you expext for non-existing keys? If yuo want to remove this values from map use

val m1: Map[Int, Char] = Map(1 -> 'A', 2 -> 'C', 3 -> 'Z')
val m2: Map[Char, String] = Map('A' -> "Andy", 'Z' -> "Zee", 'D' -> "David")
val m3: Map[Int, String] = m1.filter(x => m2.contains(x._2)).map(x => x._1 -> m2(x._2))
//Map(1 -> Andy, 3 -> Zee)

Skipping .filter(x => m2.contains(x._2)) with throw an exception for this situations

Upvotes: 2

Related Questions