scala中创建时间序列
介绍
刚接触Scala的学生的一个常见问题是:在列表上使用map函数,for表达式和foreach循环之间有什么区别? 关于此问题的主要困惑之一是,Scala中的for表达式不等同于Python和Java等语言中的for循环 -而是,Scala中的foreach等同于for循环。 这种区别凸显了理解返回值的含义与依靠副作用执行某些计算的重要性。 它还有助于加强关于固定变量与可重新分配变量以及不可变变量与可变数据结构的一些观点。
任务及其功能解决方案
为了说明这一点,让我们考虑一个简单的任务。 给定一个单词列表 ,计算两个列表:一个列出每个单词的长度,第二个表明单词是否以大写字母开头。 例如,从下面的列表开始。
scala> val words = List("This", "is", "a", "list", "of", "English", "words", ".")
words: List[java.lang.String] = List(This, is, a, list, of, English, words, .)
我们可以通过映射单词列表来计算两个列表,如下所示。
scala> words.map(_.length)
res0: List[Int] = List(4, 2, 1, 4, 2, 7, 5, 1)
scala> words.map(_(0).isUpper)
res1: List[Boolean] = List(true, false, false, false, false, true, false, false)
就是这样了。 但是,我们无需使用对map函数的不同调用(或多个foreach循环,如下所示)就可以做到这一点。 最简单的方法是将每个单词映射到一个元组,该元组包含长度和指示第一个字符是否大写的布尔值; 这将产生一个元组列表,我们将其解压缩以获得一个Lists元组。
scala> val (wlengthsMapUnzip, wcapsMapUnzip) =
| words.map(word => (word.length, word(0).isUpper)).unzip
wlengthsMapUnzip: List[Int] = List(4, 2, 1, 4, 2, 7, 5, 1)
wcapsMapUnzip: List[Boolean] = List(true, false, false, false, false, true, false, false)
这里的关键是map函数将List [String ]词转换为List [(Int,Boolean)] -也就是说它返回一个值。 我们可以将该值分配给变量,或通过对其调用解压缩立即使用它,这反过来会返回一个值为Tuple2(List [Int],List [Boolean])的值 。
在继续之前,让我们定义一个简单的函数来显示执行此计算的结果,我们将以各种方式进行此操作(并且所有这些都产生完全相同的结果)。
def display (intro: String, wlengths: List[Int], wcaps: List[Boolean]) {
println(intro)
println("Lengths: " + wlengths.mkString(" "))
println("Caps: " + wcaps.mkString(" "))
println
}
通过上面的映射和解压缩的结果调用此函数,我们得到以下输出。
scala> display("Using map and unzip.", wlengthsMapUnzip, wcapsMapUnzip)
Using map and unzip.
Lengths: 4 2 1 4 2 7 5 1
Caps: true false false false false true false false
好的,现在让我们开始努力吧。 而不是映射到原始列表,我们将使用foreach在列表上循环,并执行副作用计算以构建两个结果序列。 这种事情通常是在非功能性语言中使用for循环完成的,因此在Scala中使用了foreach 。 我们将依次探索其中的每一个。
第二种变体:使用可重新分配的不可变列表
我们可以使用可重新分配的变量,这些变量被初始化为空列表,然后在遍历单词列表时将其放在前面。 因此,我们使用的变量类型为List ,这是一个不变的序列数据结构,但是每次通过循环时,它的值都会重新分配。
var wlengthsReassign = List[Int]()
var wcapsReassign = List