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

Problem

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

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)

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

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:

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的函数。

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

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是一样:

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> 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)


转载于:https://my.oschina.net/nenusoul/blog/657510

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值