第十章 Scala 容器基础(十四):使用map把一个集合转化为另外一个

Problem

    像上一节同样,你想把一个集合的每一个元素经过某种算法变换后生成一个新的集合
es6

Solution

    咱们要调用集合的map方法,而后传给它一个函数、匿名函数或者方法来对每个集合元素进行变换,而不是for/yield。下面这个例子中咱们能够看到,咱们把一组字符串的首字母变为大写:算法

scala> val helpers = Vector("adam", "kim", "melissa")
helpers: scala.collection.immutable.Vector[String] = Vector(adam, kim, melissa)

scala> helpers.map(e => e.capitalize)
res26: scala.collection.immutable.Vector[String] = Vector(Adam, Kim, Melissa)

scala> helpers.map(_.capitalize)
res1: scala.collection.immutable.Vector[String] = Vector(Adam, Kim, Melissa)

    在下面这个例子中,咱们把一个字符串集合转化成了一个整形集合:api

scala> val names = Array("Fred", "Joe", "Jonathan")
names: Array[String] = Array(Fred, Joe, Jonathan)

scala> val lengths = names.map(_.length)
lengths: Array[Int] = Array(4, 3, 8)

    一样地,map方法能够把一个集合转化为一个xml元素:数组

scala> val nieces = List("Aleka", "Christina", "Molly")
nieces: List[String] = List(Aleka, Christina, Molly)

scala> val elems = nieces.map(niece => <li>{niece}</li>)
elems: List[scala.xml.Elem] = List(<li>Aleka</li>, <li>Christina</li>, <li>Molly</li>)

    咱们可使用相似的方法,把一个集合转化为ul:app

scala> val ul = <ul>{nieces.map(niece => <li>{niece}</li>)}</ul>
ul: scala.xml.Elem = <ul><li>Aleka</li><li>Christina</li><li>Molly</li></ul>

    被传入map方法的函数能够是任意复杂度的,固然函数的负责度这是根据你的需求来制定的。在Discussion中你会看到如何在map中使用一个多行匿名函数。当你的算法足够复杂,直到匿名函数没法知足你的需求的时候,你能够先定义一个函数,而后把这个函数传给map方法。函数

scala> def plusOne(c: Char): Char = (c.toByte+1).toChar
plusOne: (c: Char)Char

scala> "HAL".map(plusOne)
res2: String = IBM

    当你想定义一个可以传入map方法的函数的时候,这个函数必须只有一个和集合元素同类型的参数。在上面这个例子中,plusOne被定义为接受一个char,由于String世界上就是一个char的集合元素。函数的返回值能够是任何你想要的。实际上names.map(_.length)就是这么一个输入String,输出Int的函数。ui

    和for/yield结构不相同的地方是map方法能够造成一个方法调用链。也就是你能够在map方法后直接对map返回的集合进行其它操做活着把map加在一个返回集合的方法的后面。好比,你能够把一个字符串根据某中规则切分红一个字符串数组,而后再去掉字符串两边的空格。
es5

scala> val s = " eggs, milk, butter, Coco Puffs "
s: String = " eggs, milk, butter, Coco Puffs "

scala> val items = s.split(",").map(_.trim)
items: Array[String] = Array(eggs, milk, butter, Coco Puffs)

Discussion

    对于简单一点的状况来讲,使用map和使用for/yield是同样:spa

scala> val people = List("adam", "kim", "melissa")
people: List[String] = List(adam, kim, melissa)

scala> val caps1 = people.map(_.capitalize)
caps1: List[String] = List(Adam, Kim, Melissa)

scala> val caps2 = for (f <- people) yield f.capitalize
caps2: List[String] = List(Adam, Kim, Melissa)

    可是一旦当你添加guard(警卫)的时候,for/yield便可购就再也不直接等于map方法调用了。拂过你尝试使用if字句在你的算法中,而后把这个函数传递给map方法,你会发现你获得了与你想象中不一样的结果:scala

scala> val fruits = List("apple", "banana", "lime", "orange", "raspberry")
fruits: List[String] = List(apple, banana, lime, orange, raspberry)

scala> fruits.map{ fruit => {
     | if(fruit.length < 6) fruit.toUpperCase
     | }}
res5: List[Any] = List(APPLE, (), LIME, (), ())

    这样是不行的,可是你可使用filter方法来对集合元素进行过滤,而后再执行map方法调用:

scala> fruits.filter(_.length < 6).map(_.toUpperCase)
res6: List[String] = List(APPLE, LIME)
相关文章
相关标签/搜索