map和mapValues在这个例子中如何工作?

时间:2013-08-29 14:39:02

标签: scala

下面的代码将字符串转换为二进制表示形式,所以

1 = 1,1,0,0
2 = 1,1,1,0
3 = 1,1,0,1
4 = 1,1,0,0

 Returns

4-->1100
1-->1100
2-->1110
3-->1101

代码:

import scala.collection.immutable.HashMap

object BinaryRepFunctional extends Application {
  val userDetails = HashMap("1" -> "ab",
                            "2" -> "abc",
                            "3" -> "abd",
                            "4" -> "ab")
  val lettersToCheck = "abcd"

  def getBinaryRepresentation = userDetails.mapValues(
      string => lettersToCheck.map(
          letter => if (string.contains(letter)) '1' else '0'))

  getBinaryRepresentation foreach ( (t2) => println (t2._1 + "-->" + t2._2))
}

这是mapValues的签名:

override def mapValues[C](f: B => C): Map[A, C] = 
  new MappedValues(f) with DefaultMap[A, C]

这是Map的签名,因此它接受函数参数并应用它 函数到被调用集合中的每个条目。

  def map[B, That](f: A => B)(implicit bf: CanBuildFrom[Repr, B, That]): That = {
    def builder = { // extracted to keep method size under 35 bytes, so that it can be JIT-inlined
      val b = bf(repr)
      b.sizeHint(this)
      b
    }
    val b = builder
    for (x <- this) b += f(x)
    b.result
  }

函数getBinaryRepresentation可以更明确,因为我很难理解它是如何工作的吗?

2 个答案:

答案 0 :(得分:2)

如果你不理解当前形式的getBinaryRepresentation,这可能是因为你不熟悉函数式编程概念吗?

map方法通常从AB采用函数,并将其应用于A集合的每个元素,以便创建集合B的。{例如,给定Function1[Int, Int]定义为x => x + 1(即增量运算符),可以将其映射到集合[1, 7, 42]以提供[2, 8, 43]。或者考虑

val lengthFn: Function1[String, Int] = { s => s.length }
val myColl = List("London", "Paris")
myColl map lengthFn   // returns List(6, 5)

这就是地图的作用。 mapValues非常相似 - 它只是一个专门的版本,它作用于Map并转换该Map中的每个值。所以扩展上面的例子:

val capitals = Map("England" -> "London", "France" -> "Paris")
capitals mapValues lengthFn    // returns Map("England" -> 6, "France" -> 5)

如果您理解,getBinaryRepresentation的定义很简单。它采用userDetails地图,并对其每个值应用变换(因此结果将是具有相同键但不同值的地图)。

应用于每个值string的函数是

lettersToCheck.map(letter => if (string.contains(letter)) '1' else '0'))

这次是应用映射,这次是lettersToCheck列表(StringList[Char])。依次根据函数转换每个字符:

if (string.contains(letter)) '1' else '0'

所以列表中的每个字母都映射到'1''0',具体取决于string是否包含它。这意味着根据每个键中包含的字母,应用于每个值的映射结果将是一个由1和0组成的四个字符的字符串。

因此整个事物的结果是一个Map,其中值是从内部函数返回的这些四字符1和0字符串。当你了解它时,它是直截了当的,但我可以理解,如果你只是在map的实现中遵循代码行,而不理解意味着什么,那将会令人困惑。

答案 1 :(得分:0)

您的userDetails地图包含每个条目12,等等,结果的表示形式,但位用字母替换。例如,对于键3,值为abd,这意味着应设置左起第1位,第2位和第4位(从1开始)。函数getBinaryRepresentation遍历abcd中存储的字母lettersToCheck,并且对于每个字母,插入结果字符串01,具体取决于是否字母apears在相应的条目中。

鉴于位串最多为4位长,只需将1和0的字符串直接存储在映射中并完全避免任何转换就会简单得多。您的代码就变得如此简单:

object BinaryRepFunctional extends Application {
  val userDetails = HashMap("1" -> "1100",
                        "2" -> "1110",
                        "3" -> "1101",
                        "4" -> "1100")
  userDetails foreach ( (t2) => println (t2._1 + "-->" + t2._2))
}