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