5.数组
几乎所有语言都会提供数组这种数据结构。数组这种数据结构具有取值快、更新快、追加快的优点。当然也有缺点
,比如说插入慢、删除慢等(插入删除针对ArrayBuffer)。本节我们就来看下Scala中的数组
1.定长数组
Scala中使用Array来表示长度不变的数组,Scala中的Array是易变的(即数组元素支持更新操作)
我们创建一个数组,可以使用Array类的伴生对象的apply方法进行创建。由于在scala中直接输入伴生对象()就会调用
伴生对象的apply方法。所以我们可以书写如下代码:
val numbers = Array(1,2,3,4)
上述代码生成了一个存取Int类型数值的数组,该数组的长度的4。
我们要根据数组的index得到数组的值,可以使用:
val first = numbers(0)
数组下标从0开始.numbers(i)这种写法其实是调用了Array类的apply方法。
由于Scala中的Array是易变的,那么我们应该如何更新数组的元素呢?请看如下代码:
numbers(3) = 100
上述代码把数组中第四个元素的值更新为100。numbers(i)=num这种语法实际上是调用了Array类的update方法。
Scala中还通过隐式转换调用ArrayOps类为Array类增加了不少可以间接调用的方法。
除了使用伴生对象来实例化Array类,我们还可以直接new Array类的实例,实例化Array类的实例的时候要制定类型参数,如下:
val players = new Array[String](5) players(0)="James" players(1)="Kobe" players(2)="Curry" players(3)="Westbrook" players(4)="Bosh"
完整的代码如下:
2.变长数组
在Java中ArrayList是变长的数组,当数组容量用完的时候,ArrayList会去申请额外的空间,并把原来的数组元素复制过去。
在Scala中变长数组的实现类为ArrayBuffer。
Scala中的类一般都有非常多的方法,我们不可能再次一一列举。感兴趣的读者应该去通读一遍scala doc。
直接上代码:
package chapter03 import scala.collection.mutable.ArrayBuffer object TestArrayBuffer extends App { //ArrayBuffer可以通过ArrayBuffer的伴生对象来实例化,可以直接new ArrayBuffer类的实例 //通过ArrayBuffer的伴生对象实例化一个ArrayBuffer的实例。 val players = ArrayBuffer("James") //取出可变数组的第一个元素,会调用ArrayBuffer类的apply方法 println(players(0)) //往尾部添加一个元素 players += "Kobe" //往尾部添加多个元素,括号中实际上是可变参数 players += ("Curry","Westbrook") //往尾部添加一个Array players ++= Array("Bosh","Duncan") //打印数组元素 for(player <- players) print(player+" ") //从数组尾部删除元素是个高效的操作,因为不会导致其他元素的移动,尾部删除使用如下方法,参数是从尾部删除的元素的个数 players trimEnd 1 //从可变数组中间删除或者插入元素是低效的。因为会导致其他元素的移动。 //我们可以使用insert在可变数组的任意位置插入元素 players.insert(2, "Parker") //insert还有另外一个重写的方法,接受可变参数,可以传入多个元素,如下: players.insert(1,"Leonard","Ginobili") //删除元素,指定数组下标即可 players.remove(players.length-1) //删除元素,有一个重载的方法,能够指定要删除的元素的个数 players.remove(0,2) //由于ArrayBuffer是可变的,跟函数式编程的理念有点背道而驰。所以做完所有操作,最好把它转成Array在使用 players.toArray }
3.数组的遍历
Scala中数组的遍历跟Java中不太一样。scala遍历数组跟其他函数式语言遍历数组的方式基本一致。看下代码即可:
package chapter03 object 遍历数组 extends App { //定义一个不变数组 val words = Array("a","b","c","d") //如果遍历数组的时候,需要使用到数组小标的话,我们可以通过如下方式遍历数组 for(i <- 0 until words.length) println(i+" : "+ words(i)) //如果要两个元素一跳,可以这样遍历: for(i <- 0 until (words.length,2)) println(i+" : "+ words(i)) //如果要从数组尾部开始遍历数组的话,可以这样遍历: for(i <- (0 until words.length).reverse) println(i+" : "+ words(i)) //如果遍历过程中使用不到数组下标,可以使用入下语法进行遍历 for(word <- words) println(word) }
数组的其他一些易用点:
package test import scala.collection.mutable.ArrayBuffer object 数组测试 extends App { val arr = Array(1,2,3,4) val arrBuff = ArrayBuffer(1,2,3,4) //通过打印发现Array没有实现toString println(arr) //通过打印发现ArrayBuffer实现了toString println(arrBuff) //返回数组的和,数组中的对象必须是数值类型 println(arrBuff.sum) //返回数组的最大值 println(arrBuff.max) }
4.生成新的数组
Scala的Array上定义了一组方法。在Array调用这些方法不会修改原始数组,而是会生成一个新的数组。看代码:
package chapter03 object 生成新的数组 extends App { //可以利用for推导式生成新的数组 val a = Array(1,2,3,4,5,6,7) val result = for(elem <- a) yield 2*elem for(r <- result) print(r+" ") println() //可以在for推导式中利用守卫进行过滤操作,如下:找出数组中的偶数 val result2 = for(elem <- a if elem%2==0) yield elem for(r <- result2) print(r+" ") println() //可以是使用filter函数,如下 val result3 = a.filter((x:Int)=>x%2==0) for(r <- result3) print(r+" ") }
5.数组元素排序
Scala中的数组排序使用到了Ordering特质。Array类的排序方法sorted会隐式转换为对ArrayOps的调用。
为了降低问题的复杂度,我们以ArrayBuffer的排序为例来讲解。
在Scala中对象排序一般借助于Ordering特质。Ordering特质中有一个抽象方法compare。如下:
所以在数组元素比较大小的时候,我们只需给sorted方法传入Ordering的实现类即可。下看一个简单的例子:
package test import scala.collection.mutable.ArrayBuffer object 数组排序 extends App { val numbers = ArrayBuffer(8,2,4,1,9,5) val sorted = numbers.sorted //使用mkString方法,指定分割字符,可以快速打印出数组。 println(sorted mkString " " ) }
上述完成了对Array[Int]数组的排序。细心的读者可能已经发现我们并没有给sorted方法传入Ordering的实现类啊
。要解释这个问题,我们需要看一下sorted类的签名:
从上述方法中可以看出sorted类接受一个Ordering类参数,而且该参数是个隐式参数。而Ordering类的伴生对象中还定义了很多
隐式对象,如下:
其实在Scala中所有的继承自AnyVal的类T都不需要手动实现Ordering[T],因为Scala已经帮你实现好了。
比如Ordering[Int]的实现类实际上是BigInt(不是scala.math包中的BigInt)。如下:
正是因为上述的原因,我们才不需要为继承自AnyVal的类自行实现Ordering。
甚至Ordering[String]也不用手动实现(Ordering的伴生对象已经帮我们实现了)
package test import scala.collection.mutable.ArrayBuffer object 简单数组排序 extends App { val numbers = ArrayBuffer(8,2,4,1,9,5) //Ordering的伴生对象已经帮我们实现了Ordering[Int]了,直接使用即可 val sorted = numbers.sorted //使用mkString方法,指定分割字符,可以快速打印出数组。 println(sorted mkString " " ) //排序的时候还可以指定排序算法,这次倒序排列 val sorted2 = numbers.sorted(new scala.math.Ordering[Int](){ def compare(x:Int, y:Int):Int=y-x }) println(sorted2 mkString " " ) //Ordering的伴生对象已经帮我们实现了Ordering[String]了,直接使用即可应用 val players = ArrayBuffer("g","f","t","a") val sorted3 = players.sorted println(sorted3 mkString " " ) }
下面看几个复杂的数组排序的例子,如下:
package test object 复杂数组排序 extends App { //定义一个复杂的数组 val pairs = Array(("a", 5, 2), ("c", 3, 1), ("b", 1, 3)) //我们按照第二个字段排序,需要自定义Ordering val sorted = pairs.sorted(new scala.math.Ordering[(String,Int,Int)](){ def compare(x:(String,Int,Int),y:(String,Int,Int)):Int={ x._2 - y._2 } }) println(sorted mkString " ") //下面演示,如何先按照第三个字段排序,在按照第一个排序,使用自定义Ordering val pairs2 = Array(("a", 5, 3), ("c", 3, 1), ("b", 1, 3)) //自定义实现Ordering的compare方法 val sorted2 = pairs2.sorted(new scala.math.Ordering[(String,Int,Int)](){ def compare(x:(String,Int,Int),y:(String,Int,Int)):Int={ if(x._3>y._3) 1 else if(x._3<y._3) -1 else x._1.compareTo(y._1) } }) println(sorted2 mkString " ") //其实scala中Ordering自带了两个方法,简化了上述的代码,如下: //我们按照第二个字段排序 val sorted3 = pairs.sorted(Ordering.by[(String,Int,Int),Int]((x:(String,Int,Int))=>x._2) ) //下面演示,如何先按照第三个字段排序,在按照第一个排序 val sorted4 = pairs2.sorted(Ordering[(Int, String)].on[(String,Int,Int)]((x:(String,Int,Int)) => (x._3, x._1))) println(sorted4 mkString " ") }
6.二维数组
二维数组不想多说,看如下例子即可:
package test object 多维数组 extends App { //用Array的伴生对象定义数组,第二维的长度都不相同 val matrix = Array[Array[Int]](Array(1),Array(1,2),Array(1,2,3)) for(m <- matrix;n <- m) print(n+" ");println() println(matrix(0).length) println(matrix(1).length) println(matrix(2).length) //使用ofDim来创建各维长度都相同的二维数组 val matrix2 = Array.ofDim[Int](3, 3); matrix2(1)(1)=1 println(matrix2(0).length) println(matrix2(1).length) println(matrix2(2).length) }
7.scala数组和Java的互操作
Scala中的数组可以利用Scala的隐式转换和Java的List进行互相转换。直接上代码,用到时回来查
package test //把scala中的buffer转换为Java中的List import scala.collection.JavaConversions.bufferAsJavaList //把Java中的List转换为scala中的buffer import scala.collection.JavaConversions.asScalaBuffer import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.Buffer object 与Java互操作 extends App { val commond = ArrayBuffer("ls"," -al","/home") //把scala中的buffer转换为Java中的List val pb = new ProcessBuilder(commond) pb.start() //把Java中的List转换为scala中的buffer val cmd:Buffer[String] = pb.command() }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。