第十章 Scala 容器基础(十三):使用for yield转化集合

Problem

    你想要对一个原有集合的元素经过某种算法进行处理,而后生成一个新的集合。算法

Solution

    使用for/yield结构外加你的算法就能够从一个原有集合建立一个新的集合。首先咱们要有一个集合app

scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)

    使用for/yield建立一个集合的拷贝:ui

scala> for(e <- a) yield e
res12: Array[Int] = Array(1, 2, 3, 4, 5)

    你能够建立一个新的集合,经过对原有集合的每一个元素翻倍,也能够把原集合的元素变为1/2编码

scala> for(e <- a) yield e * 2
res14: Array[Int] = Array(2, 4, 6, 8, 10)

scala> for(e <- a) yield e / 2
res16: Array[Int] = Array(0, 1, 1, 2, 2)

    把一组字符串转化为大写:spa

scala> for(fruit <- fruits) yield fruit.toUpperCase
res17: scala.collection.immutable.Vector[String] = Vector(APPLE, BANANA, LIME, ORANGE)

    你的算法能够返回任何你想要的集合,下面咱们来把一个集合转化为2元组:scala

scala> for (i <- 0 until fruits.length) yield (i, fruits(i))
res18: scala.collection.immutable.IndexedSeq[(Int, String)] = Vector((0,apple), (1,banana), (2,lime), (3,orange))

    下面这个算法,返回原集合元素与元素长度组成的二元祖:
code

scala> for(fruit <- fruits) yield (fruit, fruit.length)
res20: scala.collection.immutable.Vector[(String, Int)] = Vector((apple,5), (banana,6), (lime,4), (orange,6))

    定义一个case class Person,而后根据一组姓名来建立Person集合:字符串

scala> case class Person (name: String)
defined class Person

scala> val friends = Vector("Mark", "Regina", "Matt")
friends: scala.collection.immutable.Vector[String] = Vector(Mark, Regina, Matt)

scala> for (f <- friends) yield Person(f)
res21: scala.collection.immutable.Vector[Person] = Vector(Person(Mark), Person(Regina), Person(Matt))

    你能够在for/yield语句中添加if来对原有集合元素进行过滤:it

scala> val x = for (e <- fruits if e.length < 6) yield e.toUpperCase
x: scala.collection.immutable.Vector[String] = Vector(APPLE, LIME)

Discussion

    for循环和yield的结合能够看做是for表达式活着序列表达式。它从一个原有集合的基础上返回一个新的集合。若是你是第一个使用for/yield结构,它会让你想到有一个桶活着临时区域在里边。每个来自原有集合的元素被转化而后执行yield操做,被加入到桶中。而后当循环结束的时候,桶中的全部元素被yield表达式返回。
io

    一般状况下,原集合类型决定了for/yield返回新集合的类型。若是你使用一个ArrayBuffer做为原集合,那么新集合确定也是ArrayBuffer:

scala> val fruits = scala.collection.mutable.ArrayBuffer("apple", "banana")
fruits: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(apple, banana)

scala> val x = for (e <- fruits) yield e.toUpperCase
x: scala.collection.mutable.ArrayBuffer[String] = ArrayBuffer(APPLE, BANANA)

    一个List返回一个List:

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

scala> val x = for (e <- fruits) yield e.toUpperCase
x: List[String] = List(APPLE, BANANA, ORANGE)
Using guards

    当你给for添加一个grards(警卫),而且想把代码写成多行表达式,推荐的编码风格是使用花括号而不是圆括号:

scala> val fruits = Vector("apple", "banana", "lime", "orange")
fruits: scala.collection.immutable.Vector[String] = Vector(apple, banana, lime, orange)

scala> for {
     | e <- fruits
     | if e.length < 6
     | } yield e.toUpperCase
res25: scala.collection.immutable.Vector[String] = Vector(APPLE, LIME)

    这样代码更具可读性,尤为是当你给for添加多个grards(警卫)的时候。

    当我第一次开始使用Scal的时候a,我老是使用for/yield表达式来作这样的集合转换工做,可是有一个我发现我可使用更简便的方式达到一样的目标,那就是map方法。下一节,咱们就来介绍如何使用map方法来吧一个集合转化为另外一个集合。

相关文章
相关标签/搜索