Scala List 集合使用方法

2019-05-12 19:56:15 | 编辑

Scala List 是有序不可变可重复列表,通过使用head 方法,Scala 使访问一个列表的第一个元素更加简单快速。使用tail 方法,可以访问除第一个元素之外的所有元素。访问列表中的最后一个元素需要对列表进行遍历,因此相比访问列表的头部和尾部,该操作更加昂贵。所以,列表上的大多数操作都是围绕着对头部和尾部的操作构造的。


1.定义List列表

我们可以使用List 来维护一个有序的集合。

val feeds = List("blog.toolshed.com", "pragdave.me", "blog.agiledeveloper.com")


2.List 访问元素

我们可以使用从0 到list.length - 1 的索引来访问List 中的元素。当调用feeds(1)方法时,我们使用的是List 的apply()方法。也就是说,feeds(0)是feeds.apply(0)的一个简单形式。要访问第一个元素,我们可以使用feeds(0)或者head()方法。

println(s"First feed: ${feeds.head}")
println(s"Second feed: ${feeds(1)}")

这段代码的输出结果如下:

First feed: blog.toolshed.com
Second feed: pragdave.me


3.List插入元素

如果我们想要前插一个元素,即将一个元素放在当前 List 的前面,我们可以使用特殊的::()方法。a :: list 读作“将a 前插到list”。虽然list 跟在这个操作符之后,但它是list 上的一个方法。

val prefixedList = "forums.pragprog.com/forums/87" :: feeds
println(s"First Feed In Prefixed: ${prefixedList.head}")

上述代码的输出结果如下:

First Feed In Prefixed: forums.pragprog.com/forums/87


4.Scala 合并List

假设我们想要追加一个列表到另外一个列表,例如,将listA 追加到另外一个列表list。那么我们可以使用:::()方法将list 实际上前插到listA。因此,代码应该是list ::: listA,并读作“将list 前插到listA”。因为List 是不可变的,所以我们不会影响前面的任何一个列表。我们只是使用这两个列表中的元素创建了一个新列表。下面是一个追加的例子:

val feedsWithForums =
feeds ::: List(
"forums.pragprog.com/forums/87",
"forums.pragprog.com/forums/246")
println(s"First feed in feeds with forum: ${feedsWithForums.head}")
println(s"Last feed in feeds with forum: ${feedsWithForums.last}")

下面是输出结果:

First feed in feeds with forum: blog.toolshed.com
Last feed in feeds with forum: forums.pragprog.com/forums/246


同样地,:::()方法是在操作符后面的列表上调用的。要将一个元素追加到列表中,可以使用相同的:::()方法。将想要追加的元素添加到一个列表中,然后将原始列表拼接到它的前面:

val appendedList = feeds ::: List("agilelearner.com")
println(s"Last Feed In Appended: ${appendedList.last}")

我们应该能看到下面这样的输出:

Last Feed In Appended: agilelearner.com


需要注意的是,将元素或者列表追加到另外一个列表中,实际上调用的是后者的前缀方法。这样做的原因是,与遍历到列表的最后一个元素相比,访问列表的头部元素要快得多。事半功倍。


5.List列表元素检查和过滤筛选

如果想要只选择满足某些条件的 元素,应该使用filter()方法。如果我们想要检查是否所有的feed 都满足某个特定的条件,则可以使用forall()方法。另外,如果我们想要知道是否有任意feed 满足某一条件,那么exists()方法可以帮到我们。

println(s"Feeds with blog: ${feeds.filter(_ contains "blog").mkString(", ")}")
println(s"All feeds have com: ${feeds.forall(_ contains "com")}")
println(s"All feeds have dave: ${feeds.forall(_ contains "dave")}")
println(s"Any feed has dave: ${feeds.exists(_ contains "dave")}")
println(s"Any feed has bill: ${feeds.exists(_ contains "bill")}")

我们将得到下面这样的结果:

Feeds with blog: blog.toolshed.com, blog.agiledeveloper.com
All feeds have com: false
All feeds have dave: false
Any feed has dave: true
Any feed has bill: false


6.List元素遍历操作

如果想要知道我们需要显示的每个 元素 名称的字符数,那么我们可以使用map()方法来处理每个元素,并获得一个结果列表

println(s"Feed url lengths: ${feeds.map(_.length).mkString(", ")}")

下面是输出结果:

Feed url lengths: 17, 11, 23


7.foldLeft和简化操作符

如果我们对所有元素的字符总数感兴趣,那么我们可以使用foldLeft()方法,如下所示:

val total = feeds.foldLeft(0) { (total, feed) => total + feed.length }
println(s"Total length of feed urls: $total")

上述代码的输出结果如下:

Total length of feed urls: 51


foldLeft()方法将从列表的左侧开始,为列表中的每个元素调用给定的函数值(代码块)。它将两个参数传递给该函数值,第一个参数是使用(该列表中的)前一个元素执行该函数值得到的部分结果,这就是为何其被称为“折叠”(folding)—好像列表经过这些计算折叠出结果一样。第二个参数是列表中的一个元素。部分结果的初始值被作为该方法的参数提供(在这个例子中是0)。foldLeft()方法形成了一个元素链,并在该函数值中将计算得到的部分结果值,从左边开始,从一个元素携带到下一个元素。类似地,foldRight()方法也一样,但是它从右边开始。


为了使前面的方法更加简洁,Scala 提供了替代方法。/:()方法等价于foldLeft()方法,而\:()方法等价于foldRight()方法。下面我们使用/:()方法重写前面的例子:

val total2 = (0 /: feeds) { (total, feed) => total + feed.length }
println(s"Total length of feed urls: $total2")

上述代码的输出结果如下:

Total length of feed urls: 51


现在我们可以使用 Scala 的多项约定,让代码甚至可以像下面这样更加简洁:

val total3 = (0 /: feeds) { _ + _.length }
println(s"Total length of feed urls: $total3")

下面是输出结果:

Total length of feed urls: 51