I'm trying to return a map in scala. Here's my code:
val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
// e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
// result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
val attVal = x.split(':')
attVal(0) match {
case interestRegEx(interestProduct, interestAmount) =>
Some(attVal(1).split(",").map { i =>
Map(s"$interestProduct $i" -> interestAmount)
}.reduce(_ ++ _))
case _ => None
}
}.fold(Map[String, String]())(_) //.reduce(_ + _)
The problem is trying to reduce the collection to a single Map[String, String]. I thought the fold might work, but since it doesn't perhaps I'd even need to add a reduce(_ + _)
afterwards, but that doesn't work either.
The part I don't understand is that IntelliJ tells me that interests
has type ((Equals, Equals) => Equals) => Equals
. WTF? Where are these Equals
coming from, and why isn't it just adding all of the Maps together to return a Map containing all keys & values?
If we simplify your example we will get:
val interests = Seq[String]().map { x =>
Option[Map[String, String]](Map("k" -> "v"))
}.fold(Map[String, String]())(_)
This means that we are trying to fold
Seq[Option[Map[String, String]]]
with initial value Map[String, String]()
:
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 = foldLeft(z)(op)
From fold
definition we can see that compiler expects that Option[Map[String, String]]
(each value in folding) and Map[String, String]
(init value) should be of the same type.
If you inspect Option
hierarchy you will see:
Option
-> Product
-> Equals
For Map
we have the following:
Map
-> GenMap
-> GenMapLike
-> Equals
(traits hierarchy is complicated, may be another chains exist).
So we can see tha the nearest common type is Equals
.
Second part of your puzzle is (_)
.
This is treated by compiler as an argument of lambda:
val interests = x => /*omited*/.fold(Map[String, String]())(x)
As we saw x
is (A1, A1) => A1
. And in our case it is:
(Equals, Equals) => Equals
The result of fold
is A1
which is also Equals
.
As a result lambda type is:
((Equals, Equals) => Equals) /*<< arg*/ => /*result >>*/ Equals
UPDATE:
To solve your problem I think you should use:
.flatten.reduce(_ ++ _)
When you get a trait like Product
or Equals
as the inferred type of a statement, you can usually bet you have a type mismatch in some higher order function. You typically don't get Any
or AnyRef
because those only happen if some set of types have nothing in common. One thing that sticks out to me is that your 2nd argument to fold
only takes one parameter. Amazingly enough, that typechecks, but it's probably what's giving you the types you don't expect.
I think what you wanted to do is something more like:
val interestRegEx = """(\w+) Interests \((.+ Interest)\)""".r
val singleAttributes = Seq("Sport Interests (Some Interest):Running,Swimming","Something else:True")
val interests = singleAttributes.map { x =>
// e.g. ("Sport Interests (Some Interest)", "Running,Swimming") should
// result in ("Sport Running" -> "Some Interest", "Sport Swimming" -> "Some Interest")
val attVal = x.split(':')
attVal(0) match {
case interestRegEx(interestProduct, interestAmount) =>
attVal(1).split(",").map { i =>
Map(s"$interestProduct $i" -> interestAmount)
}.reduce(_ ++ _)
case _ => Map.empty
}
}.reduce(_ ++ _)
For this I got:
scala> interests
res0: scala.collection.immutable.Map[_ <: String, String] = Map(Sport Running -> Some Interest, Sport Swimming -> Some Interest)
I got rid of the Option
wrapping the Map
s in your regex match. Since you're planning on combining the maps, may as well use the empty map as your non-match case. Then I used reduce
instead of fold
for your final match, much as you had done in the inner map
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.