【Scala学习】之SCALA 集合类

SCALA COLLECTIONS

原文地址 https://docs.scala-lang.org/overviews/scala-book/collections-101.html

如果您是从 Java 来到 Scala,那么您能做的最好的事情就是忘记 Java 集合类,并按照预期使用 Scala 集合类。 正如本书的一位作者所说,“根据个人经验,当我第一次开始使用 Scala 时,我试图在我的 Scala 代码中使用 Java 集合类,但这一切都减慢了我的进度。”

The main Scala collections classes

您将定期使用的主要 Scala 集合类是:

ClassDescription
ArrayBuffer一个索引的、可变的序列
List线性(链表),不可变序列
Vector一个索引的、不可变的序列
Map基础Map(键/值对)类
Set基础Set

MapSet 有可变和不可变版本。

我们将在以下课程中演示这些课程的基础知识。

在以下有关 Scala 集合类的课程中,无论何时我们使用不可变这个词,都可以安全地假设该类旨在用于函数式编程 (FP) 风格。 使用这些类,您无需修改集合; 您将函数方法应用于集合以创建新结果。 您将在以下示例中看到这意味着什么。

THE ARRAYBUFFER CLASS

https://docs.scala-lang.org/overviews/scala-book/arraybuffer-examples.html

如果您是一名从 Java 来到 Scala 的 OOP 开发人员,那么 ArrayBuffer 类可能最适合您,因此我们将首先演示它。 它是一个可变序列,所以你可以使用它的方法来修改它的内容,这些方法类似于 Java 序列上的方法。

要使用 ArrayBuffer,您必须首先导入它:

import scala.collection.mutable.ArrayBuffer

将其导入本地作用域后,您可以像这样创建一个空的 ArrayBuffer:

val ints = ArrayBuffer[Int]()
val names = ArrayBuffer[String]()

拥有 ArrayBuffer 后,您可以通过多种方式向其中添加元素:

val ints = ArrayBuffer[Int]()
ints += 1
ints += 2

The REPL shows how += works:

scala> ints += 1
res0: ints.type = ArrayBuffer(1)

scala> ints += 2
res1: ints.type = ArrayBuffer(1, 2)

这只是创建 ArrayBuffer 并向其添加元素的一种方法。 您还可以创建一个带有初始元素的 ArrayBuffer,如下所示:

val nums = ArrayBuffer(1, 2, 3)

您可以通过以下几种方法向此 ArrayBuffer 添加更多元素:

val nums = ArrayBuffer(1, 2, 3)

您可以通过以下几种方法向此 ArrayBuffer 添加更多元素:

// add one element
nums += 4

// add multiple elements
nums += 5 += 6

// add multiple elements from another collection
nums ++= List(7, 8, 9)

您可以使用 -=--= 方法从 ArrayBuffer 中删除元素:

// remove one element
nums -= 9

// remove multiple elements
nums -= 7 -= 8

// remove multiple elements using another collection
nums --= Array(5, 6)

下是所有这些示例在 REPL 中的样子:

scala> import scala.collection.mutable.ArrayBuffer

scala> val nums = ArrayBuffer(1, 2, 3)
val nums: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3)

scala> nums += 4
val res0: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

scala> nums += 5 += 6
val res1: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)

scala> nums ++= List(7, 8, 9)
val res2: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9)

scala> nums -= 9
val res3: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)

scala> nums -= 7 -= 8
val res4: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4, 5, 6)

scala> nums --= Array(5, 6)
val res5: ArrayBuffer[Int] = ArrayBuffer(1, 2, 3, 4)

More ways to work with ArrayBuffer

为简要概述,以下是您可以与 ArrayBuffer 一起使用的几种方法:

val a = ArrayBuffer(1, 2, 3)         // ArrayBuffer(1, 2, 3)
a.append(4)                          // ArrayBuffer(1, 2, 3, 4)
a.append(5, 6)                       // ArrayBuffer(1, 2, 3, 4, 5, 6)
a.appendAll(Seq(7,8))                // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8)
a.clear                              // ArrayBuffer()

val a = ArrayBuffer(9, 10)           // ArrayBuffer(9, 10)
a.insert(0, 8)                       // ArrayBuffer(8, 9, 10)
a.insertAll(0, Vector(4, 5, 6, 7))   // ArrayBuffer(4, 5, 6, 7, 8, 9, 10)
a.prepend(3)                         // ArrayBuffer(3, 4, 5, 6, 7, 8, 9, 10)
a.prepend(1, 2)                      // ArrayBuffer(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
a.prependAll(Array(0))               // ArrayBuffer(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

val a = ArrayBuffer.range('a', 'h')  // ArrayBuffer(a, b, c, d, e, f, g)
a.remove(0)                          // ArrayBuffer(b, c, d, e, f, g)
a.remove(2, 3)                       // ArrayBuffer(b, c, g)

val a = ArrayBuffer.range('a', 'h')  // ArrayBuffer(a, b, c, d, e, f, g)
a.trimStart(2)                       // ArrayBuffer(c, d, e, f, g)
a.trimEnd(2)                         // ArrayBuffer(c, d, e)

THE LIST CLASS

https://docs.scala-lang.org/overviews/scala-book/list-class.html

List 类是一个线性的、不可变的序列。 所有这一切都意味着它是一个无法修改的链表。 任何时候您想要添加或删除 List 元素,您都可以从现有 List 创建一个新 List。

Creating Lists

这是您创建初始列表的方式:

val ints = List(1, 2, 3)
val names = List("Joel", "Chris", "Ed")

如果您愿意,您也可以声明 List 的类型,但通常没有必要:

val ints: List[Int] = List(1, 2, 3)
val names: List[String] = List("Joel", "Chris", "Ed")

Adding elements to a List

因为 List 是不可变的,所以你不能向它添加新元素。 相反,您可以通过在现有列表中添加或添加元素来创建新列表。 例如,给定这个列表:

val a = List(1,2,3)

您将元素添加到列表中,如下所示:

val b = 0 +: a
val b = List(-1, 0) ++: a

REPL 展示了这是如何工作的:

scala> val b = 0 +: a
b: List[Int] = List(0, 1, 2, 3)

scala> val b = List(-1, 0) ++: a
b: List[Int] = List(-1, 0, 1, 2, 3)

您也可以将元素附加到 List,但是因为 List 是一个单向链表,所以您应该只在它前面添加元素; 向其中添加元素是一个相对较慢的操作,尤其是在处理大型序列时。

提示:如果您想在不可变序列中添加和附加元素,请改用 Vector。

因为 List 是一个链表类,你不应该尝试通过索引值访问大列表的元素。 例如,如果您有一个包含一百万个元素的 List,那么访问像 myList(999999) 这样的元素将需要很长时间。 如果要访问这样的元素,请改用 Vector 或 ArrayBuffer。

How to remember the method names

如今,IDE 为我们提供了极大的帮助,但是记住这些方法名称的一种方法是认为 : 字符代表序列所在的一侧,因此当您使用 +: 时,您知道列表需要在右侧 , 像这样:

 0 +: a

同样,当您使用 :+ 时,您知道列表需要在左侧:

a :+ 4

有更多的技术方法可以考虑这一点,这可以是一种记住方法名称的简单方法。

这些方法名称的一个好处是:它们是一致的。 相同的方法名称用于其他不可变序列类,例如 Seq 和 Vector。

How to loop over lists

我们在本书前面展示了如何循环列表,但值得再次展示语法。 给定一个这样的列表:

val names = List("Joel", "Chris", "Ed")

您可以像这样打印每个字符串:

for (name <- names) println(name)

这是它在 REPL 中的样子:

scala> for (name <- names) println(name)
Joel
Chris
Ed

这种方法的一大优点是它适用于所有序列类,包括 ArrayBuffer、List、Seq、Vector 等。

A little bit of history

如果您对一点历史感兴趣,List 类与 Lisp 编程语言中的 List 类非常相似。 事实上,除了像这样创建一个列表:

val ints = List(1, 2, 3)

您也可以通过这种方式创建完全相同的列表:

val list = 1 :: 2 :: 3 :: Nil

The REPL shows how this works:

scala> val list = 1 :: 2 :: 3 :: Nil
list: List[Int] = List(1, 2, 3)

这是有效的,因为 List 是一个以 Nil 元素结尾的单向链表。

THE VECTOR CLASS

https://docs.scala-lang.org/overviews/scala-book/vector-class.html

Vector 类是一个索引的、不可变的序列。 描述的“索引”部分意味着您可以通过索引值非常快速地访问 Vector 元素,例如访问 listOfPeople(999999)。

一般来说,除了 Vector 有索引而 List 没有索引的区别外,这两个类的工作方式相同,因此我们将快速浏览这些示例。

以下是创建 Vector 的几种方法:

val nums = Vector(1, 2, 3, 4, 5)

val strings = Vector("one", "two")

val peeps = Vector(
    Person("Bert"),
    Person("Ernie"),
    Person("Grover")
)

因为 Vector 是不可变的,所以你不能向它添加新元素。 相反,您可以通过向现有 Vector 附加或预先添加元素来创建新序列。 例如,给定这个向量:

val a = Vector(1,2,3)

你附加这样的元素:

val b = a :+ 4
val b = a ++ Vector(4, 5)

The REPL shows how this works:

scala> val a = Vector(1,2,3)
a: Vector[Int] = Vector(1, 2, 3)

scala> val b = a :+ 4
b: Vector[Int] = Vector(1, 2, 3, 4)

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

您还可以预先添加这样的元素:

val b = 0 +: a
val b = Vector(-1, 0) ++: a

REPL 再次展示了这是如何工作的:

scala> val b = 0 +: a
b: Vector[Int] = Vector(0, 1, 2, 3)

scala> val b = Vector(-1, 0) ++: a
b: Vector[Int] = Vector(-1, 0, 1, 2, 3)

因为 Vector 不是链表(如 List),您可以在其前面添加和附加元素,并且两种方法的速度应该相似。

最后,您可以像处理 ArrayBuffer 或 List 一样遍历 Vector 中的元素:

scala> val names = Vector("Joel", "Chris", "Ed")
val names: Vector[String] = Vector(Joel, Chris, Ed)

scala> for (name <- names) println(name)
Joel
Chris
Ed

THE MAP CLASS

https://docs.scala-lang.org/overviews/scala-book/map-class.html

Map 类文档将 Map 描述为由键和值对组成的可迭代序列。 一个简单的 Map 如下所示:

val states = Map(
    "AK" -> "Alaska",
    "IL" -> "Illinois",
    "KY" -> "Kentucky"
)

Scala 有可变和不可变的 Map 类。 在本课中,我们将展示如何使用可变类。

Creating a mutable Map

要使用可变 Map 类,首先导入它:

import scala.collection.mutable.Map

然后你可以像这样创建一个Map:

val states = collection.mutable.Map("AK" -> "Alaska")

Adding elements to a Map

现在您可以使用 += 向 Map 添加单个元素,如下所示:

states += ("AL" -> "Alabama")

您还可以使用 += 添加多个元素:

states += ("AR" -> "Arkansas", "AZ" -> "Arizona")

您可以使用 ++= 从另一个 Map 添加元素:

states ++= Map("CA" -> "California", "CO" -> "Colorado")

The REPL shows how these examples work:

scala> val states = collection.mutable.Map("AK" -> "Alaska")
states: scala.collection.mutable.Map[String,String] = Map(AK -> Alaska)

scala> states += ("AL" -> "Alabama")
res0: states.type = Map(AL -> Alabama, AK -> Alaska)

scala> states += ("AR" -> "Arkansas", "AZ" -> "Arizona")
res1: states.type = Map(AZ -> Arizona, AL -> Alabama, AR -> Arkansas, AK -> Alaska)

scala> states ++= Map("CA" -> "California", "CO" -> "Colorado")
res2: states.type = Map(CO -> Colorado, AZ -> Arizona, AL -> Alabama, CA -> California, AR -> Arkansas, AK -> Alaska)

Removing elements from a Map

您可以使用 -= 和 --= 并指定键值从 Map 中删除元素,如以下示例所示:

states -= "AR"
states -= ("AL", "AZ")
states --= List("AL", "AZ")

The REPL shows how these examples work:

scala> states -= "AR"
res3: states.type = Map(CO -> Colorado, AZ -> Arizona, AL -> Alabama, CA -> California, AK -> Alaska)

scala> states -= ("AL", "AZ")
res4: states.type = Map(CO -> Colorado, CA -> California, AK -> Alaska)

scala> states --= List("AL", "AZ")
res5: states.type = Map(CO -> Colorado, CA -> California, AK -> Alaska)

Updating Map elements

您可以通过将它们的键重新分配给新值来更新 Map 元素:

states("AK") = "Alaska, A Really Big State"

The REPL shows the current Map state:

scala> states("AK") = "Alaska, A Really Big State"

scala> states
res6: scala.collection.mutable.Map[String,String] = Map(CO -> Colorado, CA -> California, AK -> Alaska, A Really Big State)

Traversing a Map

有几种不同的方法可以迭代映射中的元素。Given a sample map:

val ratings = Map(
    "Lady in the Water"-> 3.0, 
    "Snakes on a Plane"-> 4.0,
    "You, Me and Dupree"-> 3.5
)

循环遍历所有地图元素的一个好方法是使用for循环语法:

for ((k,v) <- ratings) println(s"key: $k, value: $v")

foreach方法中使用match也非常易读:

ratings.foreach {
    case(movie, rating) => println(s"key: $movie, value: $rating")
}

See also

还有其他方法可以使用 Scala Maps,以及满足不同需求的 Map 类的一个很好的集合。 有关更多信息和示例,请参阅 Map 类文档

THE SET CLASS

https://docs.scala-lang.org/overviews/scala-book/set-class.html

Scala Set 类是一个没有重复元素的可迭代集合。

Scala 有可变和不可变的 Set 类。 在本课中,我们将展示如何使用可变类。

Adding elements to a Set

要使用可变 Set,首先导入它:

val set = scala.collection.mutable.Set[Int]()

您可以使用 +=、++= 和 add 方法将元素添加到可变 Set 中。 这里有一些例子:

set += 1
set += 2 += 3
set ++= Vector(4, 5)

The REPL shows how these examples work:

scala> val set = scala.collection.mutable.Set[Int]()
val set: scala.collection.mutable.Set[Int] = Set()

scala> set += 1
val res0: scala.collection.mutable.Set[Int] = Set(1)

scala> set += 2 += 3
val res1: scala.collection.mutable.Set[Int] = Set(1, 2, 3)

scala> set ++= Vector(4, 5)
val res2: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 3, 4)

请注意,如果您尝试向已经在其中的集合添加一个值,该尝试将被悄悄忽略:

scala> set += 2
val res3: scala.collection.mutable.Set[Int] = Set(1, 5, 2, 3, 4)

Set 也有一个 add 方法,如果元素被添加到集合中,则返回 true,如果没有添加,则返回 false。 REPL 展示了它是如何工作的:

scala> set.add(6)
res4: Boolean = true

scala> set.add(5)
res5: Boolean = false

Deleting elements from a Set

使用 -= 和 --= 方法从集合中删除元素,如以下示例所示:

scala> val set = scala.collection.mutable.Set(1, 2, 3, 4, 5)
set: scala.collection.mutable.Set[Int] = Set(2, 1, 4, 3, 5)

// one element
scala> set -= 1
res0: scala.collection.mutable.Set[Int] = Set(2, 4, 3, 5)

// two or more elements (-= has a varargs field)
scala> set -= (2, 3)
res1: scala.collection.mutable.Set[Int] = Set(4, 5)

// multiple elements defined in another sequence
scala> set --= Array(4,5)
res2: scala.collection.mutable.Set[Int] = Set()

有更多使用集合的方法,包括 clear 和 remove,如以下示例所示:

scala> val set = scala.collection.mutable.Set(1, 2, 3, 4, 5)
set: scala.collection.mutable.Set[Int] = Set(2, 1, 4, 3, 5)

// clear
scala> set.clear()

scala> set
res0: scala.collection.mutable.Set[Int] = Set()

// remove
scala> val set = scala.collection.mutable.Set(1, 2, 3, 4, 5)
set: scala.collection.mutable.Set[Int] = Set(2, 1, 4, 3, 5)

scala> set.remove(2)
res1: Boolean = true

scala> set
res2: scala.collection.mutable.Set[Int] = Set(1, 4, 3, 5)

scala> set.remove(40)
res3: Boolean = false

More Sets

Scala 还有几个 Set 类,包括 SortedSet、LinkedHashSet 等。 有关这些类的更多详细信息,请参阅 Set 类文档

ANONYMOUS FUNCTIONS

https://docs.scala-lang.org/overviews/scala-book/anonymous-functions.html

在本书前面,你看到你可以像这样创建一个整数列表:

val ints = List(1,2,3)

当你想创建一个更大的列表时,你也可以使用 List 类的 range 方法创建它们,如下所示:

val ints = List.range(1, 10)

该代码将整数创建为一个整数列表,其值范围从 1 到 10。您可以在 REPL 中看到结果:

scala> val ints = List.range(1, 10)
x: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9)

在本课中,我们将使用这样的列表来演示称为匿名函数的函数式编程特性。 在我们演示最常见的 Scala 集合方法之前,这将有助于理解这些是如何工作的。

Examples

匿名函数就像一个小函数。 例如,给定这样的列表:

val ints = List(1,2,3)

您可以通过将 ints 中的每个元素加倍来创建一个新列表,如下所示:

val doubledInts = ints.map(_ * 2)

This is what that example looks like in the REPL:

scala> val doubledInts = ints.map(_ * 2)
doubledInts: List[Int] = List(2, 4, 6)

如图所示,doubledInts 现在是列表 List(2, 4, 6)。 在这个例子中,这段代码是一个匿名函数:

_ * 2

这是“将一个元素乘以 2”的简写方式。

熟悉 Scala 后,这是编写匿名函数的常用方法,但如果您愿意,也可以使用更长的形式编写它们。 除了像这样编写代码:

val doubledInts = ints.map(_ * 2)

val doubledInts = ints.map((i: Int) => i * 2)
val doubledInts = ints.map(i => i * 2)

所有三行都具有完全相同的含义:将 ints 中的每个元素加倍以创建一个新列表 doubledInts。

Scala 中的 _ 字符是通配符。 你会看到它在几个不同的地方使用。 在这种情况下,它是“列表中的一个元素,整数”的简写方式。

在进一步讨论之前,值得一提的是,这个地图示例相当于这个 Java 代码:

List<Integer> ints = new ArrayList<>(Arrays.asList(1, 2, 3));

// the `map` process
List<Integer> doubledInts = ints.stream()
                                .map(i -> i * 2)
                                .collect(Collectors.toList());

显示的Map示例也与此 Scala 代码相同:

val doubledInts = for (i <- ints) yield i * 2

Anonymous functions with the filter method

另一个显示匿名函数的好方法是使用 List 类的 filter 方法。 再次给出这个列表:

val ints = List.range(1, 10)

这是创建一个包含所有值大于 5 的整数的新列表的方法:

val x = ints.filter(_ > 5)

这是创建一个值都小于 5 的新列表的方法:

val x = ints.filter(_ < 5)

作为一个稍微复杂一点的例子,这就是你如何使用模运算符创建一个只包含偶数值的新列表:

val x = ints.filter(_ % 2 == 0)

如果这有点令人困惑,请记住这个例子也可以用这些其他方式编写:

val x = ints.filter((i: Int) => i % 2 == 0)
val x = ints.filter(i => i % 2 == 0)

This is what the previous examples look like in the REPL:

scala> val x = ints.filter(_ > 5)
x: List[Int] = List(6, 7, 8, 9)

scala> val x = ints.filter(_ < 5)
x: List[Int] = List(1, 2, 3, 4)

scala> val x = ints.filter(_ % 2 == 0)
x: List[Int] = List(2, 4, 6, 8)

Key points

The key points of this lesson are:

  • 您可以将匿名函数编写为一小段代码
  • 您可以将它们与 List 类上的方法一起使用,例如 mapfilter
  • 使用这些小代码片段和强大的方法,您可以用很少的代码创建很多功能

Scala 集合类包含许多方法,如mapfilter,它们是创建极具表现力的代码的强大方法。

Bonus: Digging a little deeper

您可能想知道 mapfilter 示例是如何工作的。 简短的回答是,当在整数列表上调用 map 时——更准确地说是 List[Int]——map 期望接收一个将一个 Int 值转换为另一个 Int 值的函数 . 因为 map 需要一个函数(或方法)将一个 Int 转换为另一个 Int,所以这种方法也有效:该示例的最后两行与此相同:

val ints = List(1,2,3)
def double(i: Int): Int = i * 2   //a method that doubles an Int
val doubledInts = ints.map(double)

该示例的最后两行与此相同:

val doubledInts = ints.map(_ * 2)

类似地,当在 List[Int] 上调用时,filter 方法期望接收一个函数,该函数接受一个 Int 并返回一个布尔值。 因此,给定一个定义如下的方法:

def lessThanFive(i: Int): Boolean = if (i < 5) true else false

或者更简洁地说,像这样:

def lessThanFive(i: Int): Boolean = (i < 5)

此过滤器示例:

val ints = List.range(1, 10)
val y = ints.filter(lessThanFive)

与此示例相同:

val y = ints.filter(_ < 5)

COMMON SEQUENCE METHODS

https://docs.scala-lang.org/overviews/scala-book/collections-methods.html

Scala 集合类的一大优势在于它们带有许多预构建的方法。 这样做的好处是您不再需要在每次需要处理集合时编写自定义 for 循环。 (如果这还不够好处,这也意味着您不再需要阅读其他开发人员编写的自定义 for 循环。)

因为可供大家使用的方法太多了,这里就不一一展示了。 相反,将仅显示一些最常用的方法,包括:

  • map
  • filter
  • foreach
  • head
  • tail
  • take, takeWhile
  • drop, dropWhile
  • reduce

以下方法将适用于所有集合“序列”类,包括 Array、ArrayBuffer、List、Vector 等,但除非另有说明,否则这些示例将使用 List。

Note: The methods don’t mutate the collection

非常重要的一点是,这些方法都不会改变它们被调用的集合。 它们都以函数式风格工作,因此它们返回一个带有修改结果的新集合。

Sample lists

以下示例将使用这些列表:

val nums = (1 to 10).toList
val names = List("joel", "ed", "chris", "maurice")

This is what those lists look like in the REPL:

scala> val nums = (1 to 10).toList
nums: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> val names = List("joel", "ed", "chris", "maurice")
names: List[String] = List(joel, ed, chris, maurice)

map

map 方法遍历现有列表中的每个元素,将您提供的算法应用于每个元素,一次一个; 然后它返回一个包含所有修改过的元素的新列表。

这是应用于 nums 列表的 map 方法的示例:

scala> val doubles = nums.map(_ * 2)
doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

正如我们在匿名函数课程中所展示的,您也可以像这样编写匿名函数:

scala> val doubles = nums.map(i => i * 2)
doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

但是,在本课中,我们将始终使用第一种较短的形式。

有了这个背景,下面是一个应用到 numsnames 列表的map 方法的例子:

scala> val capNames = names.map(_.capitalize)
capNames: List[String] = List(Joel, Ed, Chris, Maurice)

scala> val doubles = nums.map(_ * 2)
doubles: List[Int] = List(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)

scala> val lessThanFive = nums.map(_ < 5)
lessThanFive: List[Boolean] = List(true, true, true, true, false, false, false, false, false, false)

正如最后一个例子所示,使用 map 返回一个与原始类型 (List[Int]) 不同类型 (List[Boolean]) 的列表是完全合法的(并且非常常见)。

filter

filter 方法从给定的列表中创建一个新的过滤列表。 这里有一些例子:

scala> val lessThanFive = nums.filter(_ < 5)
lessThanFive: List[Int] = List(1, 2, 3, 4)

scala> val evens = nums.filter(_ % 2 == 0)
evens: List[Int] = List(2, 4, 6, 8, 10)

scala> val shortNames = names.filter(_.length <= 4)
shortNames: List[String] = List(joel, ed)

foreach

foreach 方法用于循环遍历集合中的所有元素。 正如我们在上一课中提到的,foreach 用于副作用,例如打印信息。 这是名称列表的示例:

scala> names.foreach(println)
joel
ed
chris
maurice

nums 列表有点长,因此您可能不想打印出所有这些元素。 但是 Scala 方法的一个优点是您可以将方法链接在一起来解决这样的问题。 例如,这是从 nums 打印前三个元素的一种方法:

nums.filter(_ < 4).foreach(println)

The REPL shows the result:

scala> nums.filter(_ < 4).foreach(println)
1
2
3

head

head 方法来自 Lisp 和函数式编程语言。 它用于打印列表的第一个元素(头元素):

scala> nums.head
res0: Int = 1

scala> names.head
res1: String = joel

因为 String 是一个字符序列,您也可以将其视为一个列表。 这是 head 在这些字符串上的工作方式:

scala> "foo".head
res2: Char = f

scala> "bar".head
res3: Char = b

head 是一个很好的工作方法,但作为一个警告,它在调用空集合时也可能抛出异常:

scala> val emptyList = List[Int]()
val emptyList: List[Int] = List()

scala> emptyList.head
java.util.NoSuchElementException: head of empty list

tail

tail 方法也来自 Lisp 和函数式编程语言。 它用于打印列表中 head 元素之后的每个元素。 几个例子:

scala> nums.tail
res0: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> names.tail
res1: List[String] = List(ed, chris, maurice)

就像 head 一样,tail 也适用于字符串:

scala> "foo".tail
res2: String = oo

scala> "bar".tail
res3: String = ar

请注意,与 head 和 tail 一样,在空集合上调用时也会抛出异常:

scala> emptyList.tail
java.lang.UnsupportedOperationException: tail of empty list

take, takeWhile

take 和 takeWhile 方法为您提供了一种从列表中取出要创建新列表的元素的好方法。 这是保留式获取:

scala> nums.take(1)
res0: List[Int] = List(1)

scala> nums.take(2)
res1: List[Int] = List(1, 2)

scala> names.take(1)
res2: List[String] = List(joel)

scala> names.take(2)
res3: List[String] = List(joel, ed)

And this is takeWhile:

scala> nums.takeWhile(_ < 5)
res4: List[Int] = List(1, 2, 3, 4)

scala> names.takeWhile(_.length < 5)
res5: List[String] = List(joel, ed)

drop, dropWhile

drop 和 dropWhile 本质上是 take 和 takeWhile 的对立面。 这是删除式获取:

scala> nums.drop(1)
res0: List[Int] = List(2, 3, 4, 5, 6, 7, 8, 9, 10)

scala> nums.drop(5)
res1: List[Int] = List(6, 7, 8, 9, 10)

scala> names.drop(1)
res2: List[String] = List(ed, chris, maurice)

scala> names.drop(2)
res3: List[String] = List(chris, maurice)

And this is dropWhile:

scala> nums.dropWhile(_ < 5)
res4: List[Int] = List(5, 6, 7, 8, 9, 10)

scala> names.dropWhile(_ != "chris")
res5: List[String] = List(chris, maurice)

reduce

当你听到“map reduce”这个词时,reduce部分指的是像reduce这样的方法。 它接受一个函数(或匿名函数)并将该函数应用于列表中的连续元素。

解释 reduce 的最好方法是创建一个可以传递给它的小助手方法。 例如,这是一个将两个整数相加的 add 方法,并且还为我们提供了一些不错的调试输出:

def add(x: Int, y: Int): Int = {
    val theSum = x + y
    println(s"received $x and $y, their sum is $theSum")
    theSum
}

现在,鉴于该方法和此列表:

al a = List(1,2,3,4)

当你将 add 方法传递给 reduce 时会发生什么:

scala> a.reduce(add)
received 1 and 2, their sum is 3
received 3 and 3, their sum is 6
received 6 and 4, their sum is 10
res0: Int = 10

如该结果所示,reduce 使用 add 将列表 a 减少为单个值,在本例中为列表中整数的总和。

一旦你习惯了reduce,你就会写一个像这样的“求和”算法:

scala> a.reduce(_ + _)
res0: Int = 10

类似地,这就是“产品”算法的样子:

scala> a.reduce(_ * _)
res1: Int = 24

如果您以前从未见过它,那可能会有点令人兴奋,但过一段时间您就会习惯它。

在继续之前,了解 reduce 的一个重要部分是——顾名思义——它用于将集合减少到单个值。

Even more!

Scala 序列类实际上有数十种附加方法,它们将使您无需编写另一个 for 循环。 但是,由于这是一本简单的介绍书,因此不会在此处全部介绍。 有关更多信息,see the collections overview of sequence traits.。

COMMON MAP METHODS

https://docs.scala-lang.org/overviews/scala-book/collections-maps.html

在本课中,我们将演示一些最常用的 Map 方法。 在这些最初的例子中,我们将使用一个不可变的 Map,Scala 也有一个可变的 Map 类,您可以就地修改它,本课稍后会演示。

对于这些示例,我们不会将 Map 方法分解为单独的部分; 我们将在每种方法之前提供一个简短的评论。

Given this immutable Map:

val m = Map(
    1 -> "a", 
    2 -> "b", 
    3 -> "c",
    4 -> "d"
)

以下是该 Map 可用的一些方法示例:

// how to iterate over Map elements
scala> for ((k,v) <- m) printf("key: %s, value: %s\n", k, v)
key: 1, value: a
key: 2, value: b
key: 3, value: c
key: 4, value: d

// how to get the keys from a Map
scala> val keys = m.keys
keys: Iterable[Int] = Set(1, 2, 3, 4)

// how to get the values from a Map
scala> val values = m.values
val values: Iterable[String] = MapLike.DefaultValuesIterable(a, b, c, d)

// how to test if a Map contains a key
scala> val contains3 = m.contains(3)
contains3: Boolean = true

// how to transform Map values
scala> val ucMap = m.transform((k,v) => v.toUpperCase)
ucMap: scala.collection.immutable.Map[Int,String] = Map(1 -> A, 2 -> B, 3 -> C, 4 -> D)

// how to filter a Map by its keys
scala> val twoAndThree = m.view.filterKeys(Set(2,3)).toMap
twoAndThree: scala.collection.immutable.Map[Int,String] = Map(2 -> b, 3 -> c)

// how to take the first two elements from a Map
scala> val firstTwoElements = m.take(2)
firstTwoElements: scala.collection.immutable.Map[Int,String] = Map(1 -> a, 2 -> b)

请注意,最后一个示例可能仅对已排序的 Map 有意义。

Mutable Map examples

以下是可变 Map 类上可用的一些方法示例。 鉴于这个初始可变Map

val states = scala.collection.mutable.Map(
    "AL" -> "Alabama", 
    "AK" -> "Alaska"
)

Here are some things you can do with a mutable Map:

// add elements with +=
states += ("AZ" -> "Arizona")
states ++= Map("CO" -> "Colorado", "KY" -> "Kentucky")

// remove elements with -=
states -= "KY"
states --= List("AZ", "CO")

// update elements by reassigning them
states("AK") = "Alaska, The Big State"

// filter elements by supplying a function that operates on
// the keys and/or values
states.filterInPlace((k,v) => k == "AK")

See also

你可以用Map做更多的事情。 有关更多详细信息和示例,请参阅 Map 类文档

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值