Scala笔记整理(二):Scala数据结构—数组、map与tuple-创新互联
[TOC]
成都创新互联公司自成立以来,一直致力于为企业提供从网站策划、网站设计、成都做网站、成都网站设计、成都外贸网站建设、电子商务、网站推广、网站优化到为企业提供个性化软件开发等基于互联网的全面整合营销服务。公司拥有丰富的网站建设和互联网应用系统开发管理经验、成熟的应用系统解决方案、优秀的网站开发工程师团队及专业的网站设计师团队。数组
定长数组
如果你需要一个长度不变的数组,可以用Scala中的Array。例如:
val numsArray = new Array[Int] (30) //长度为30的整数数组,所有元素初始化为0
val stringArrays = new Array [String] (30) //长度为30的字符串数组,所有元素初始化为null
val sHello = Array("Hello", "World") //长度为2的Array[String]类型是推断出来的,已提供初始值就不需要new
sHello(0) = "Hello Tom",使用()而不是[]来访问元素
在JVM中,Scala的Array以Java数组方式实现。示例中的数组在JVM中的类型为java.lang.String[]。Int、Double或其他与Java中基本类型对应的数组都是基本类型数组。
举例来说,Array(2,3,5,6,7,10, 11)
在JVM中就是一个int[]。
定长数组Array-赋值
- 方法1
val stringArrays = new Array[String] (5)
stringArrays(0) = “tom”
- 方法2
val array = Array(1, 2, 3, 4, 5)
- 方法3
// Array.fill(length)(value)
val array = Array.fill(5)(3.5)
如果fill第二个参数只写一个值的话,那么该数组的所有元素都是该值,但是如果第二个参数是一个iterator
或者random
,那么数组就会被赋值为它们的值。
val array = Array.fill(2)(math.random)
变长数组ArrayBuffer
1、对于那种长度按需要变化的数组,Java有ArrayList,C++有vector。Scala中的等效数据结构为ArrayBuffer
2、ArrayBuffer是一种mutable的数据容器,相对于Array来说,大的区别就是可以自由增删元素。当ArrayBuffer构建完毕后,还可以转换为immutable的Array容器。
import scala.collection.mutable.ArrayBuffer
val buffer = ArrayBuffer[lnt]() // 或者new ArrayBuffer [int],一个空的数组缓冲,准备存放整数
buffer += 1 // ArrayBuffer (1),用+=在尾端添加元素
buffer.append(300)
buffer += (1,2,3,5) // ArrayBuffer(1,1,2,3,5),在尾端添加多个元素,以括号包起来
buffer ++= Array(8, 13, 21) // ArrayBuffer(1, 1, 2, 3, 5, 8,13, 21) //用++=操作符追加任何集合
buffer.insert(2, 150) //在第2元素(索引)后插入150:
buffer.insert(3, 147,21) //在第2元素后插入147,21:
buffer.trimEnd(5) // ArrayBuffer(1, 1, 2),移除最后5个元素,在数组缓冲的尾端添加或移除元素是一个高效的操作
buffer.remove(index, n) //移除第index元素后的n个元素
一个完整的例子如下:
import scala.collection.mutable.ArrayBuffer
object _07ArrayBufferDemo {
def main(args:Array[String]):Unit = {
val ab = new ArrayBuffer[Int]()
// 增
ab += 1
println(ab)
ab.append(2)
println(ab)
ab += (3, 4, 5)
println(ab)
ab ++= Array(6, 7)
println(ab)
// insert
ab.insert(3, -1, -2) // 可以在某一个位置插入多个元素
println(ab)
// 删
ab.trimEnd(1) // 删除数组末尾的1个元素
println(ab)
ab.remove(3, 1) // 从索引位置3开始删除,删除2个元素
println(ab)
// 改
ab(3) = -3
println(ab)
// 查
println("==============================")
for(i <- ab) {
println(i)
}
}
}
遍历数组
val array = Array(1, 2, 3, 4, 5)
1、全遍历常用遍历(//如果不需要使用下标,用这种方式最简单了)
for(i <- array) print(i +" ")
2、条件遍历
for(i <- arrayif i !=2 ) print(i +“ ”) //打印出除2之外的所有整数的值
3、For推导式
在前面,你看到了如何像Java或C++那样操作数组。不过在Scala中,你可以走得更远。从一个数组或数组缓冲出发,以某种方式对它进行转换是很简单的。这些转换动作不会修改原始数组,而是产生一个全新的数组。像这样使用for推导式:
val arr = ArrayBuffer(1, 3, 2, -1, -2)
for(i <- 0 until arr.length) yield arr(i) * 2 //将得到Vector(2, 6, 4, -2, -4)
for(i <- array) yield print(i * 2) // ArrayBuffer[Unit] = ArrayBuffer((), (), (), (), ())
另外一种等价方法(借助于函数式编程的思想),某些有着函数式编程经验的程序员倾向于使用filter和map而不是守卫和yield,这不过是一种风格罢了与for循环所做的事完全相同。你可以根据喜好任意选择:
array.filter( _ > 0).map{ 2 * _}.foreach(println(_)) //生成array中的正数的两倍的新集合
array.filter {_ > 0}.map {2 * _}.foreach(println //另一种写法
常用算法(Scala内置函数)
1、求和与排序
println(Array(1,7,2,9).sum)
2、求大值
println(ArrayBuffer("Mary","had","a","little","lamb").max)
3、排序
- 升序
val b = ArrayBuffer(1,7,2, 9)
val bSorted = b.sorted //1,2,7,9
b.sortWith(_ < ).foreach(println())
降序
b.sortWith(_ > ).foreach(println())
4、显示数组内容
println(b.mkString("And")) //分隔符
println(b.mkString("<",",",">"))//<1,7,2,9> //指定前缀、分隔符、后缀
多维数组
1、定长多维数组(和Java一样,多维数组是通过数组的数组来实现的)
val array = new Array[Array[Int]](5)
scala> val array = new Array[Array[Int]](5)
array: Array[Array[Int]] = Array(null, null, null, null, null)
2、Scala中的多维数组同Java中一样,多维数组都是数组的数组。(推荐使用这种方式)
通过 Array.ofDi[类型](维度1, 维度2, 维度3,….)
来声明多维数组,如声明二维数组;
或者也可以这么定义用ofDim[T](rows,column, height,…)
函数定义,但最多可以定义五维数组。
scala> val array = Array.ofDim[Double](2,3)
array: Array[Array[Double]] = Array(Array(0.0, 0.0, 0.0), Array(0.0, 0.0, 0.0))
scala> for(a <- array) println(a.toList)
List(0.0, 0.0, 0.0)
List(0.0, 0.0, 0.0)
3、变长多维数组
val arr1 = new ArrayBuffer[ArrayBuffer[Int]]()
定长数组和变长数组的转换
1、定长数组a转换成变长数组array:
array = a.toBuffer
2、变长数组array转换成定长数组a:
a = array.toArray
与Java互操作(了解)
由于Scala数组是用java数组实现的,你可以在Java和Scala之间来回传递。可以引入scala.collection.JavaConversions里的隐式转换方法,这样在调用Java方法时,这些对象会被自动包装成Java列表。
举例来说,java.lang.ProcessBuilder类有一个以List
- Scala到Java之间的转换工作
def conversionArray: Unit ={
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/home/cay")
val pb = new ProcessBuilder(command) // Scala到Java的转换
println(pb.command())
- Java到Scala之间的转换工作
def conversionArray: Unit ={
import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable._
val command = ArrayBuffer("ls", "-al", "/home/cay")
val pb = new ProcessBuilder(command) // Scala到Java的转换
println(pb.command())
import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val cmd: Buffer[String] = pb.command() // Java到Scala的转换
println(cmd.head +"\t tail=> " + cmd.tail)
}
Map
Map创建
1、不可变映射
我们可以这样构造一个映射:
val personAges = Map("Alice"-> 20, "Job"->28, "Garry"->18)
上述代码构造出一个不可变的Map[String,Int],其值不能被改变。
也可以用此方法创建Map
val personAges = Map(("Alice"-> 20), ("Job"->28),("Garry"->18))
注:->用来创建元组, "sa" -> 1即(" sa ", 1)
2、可变映射
如果你想要一个可变映射,则用
val personAges = scala.collection.mutable.Map("Alice"->20, "Job"->28, "Garry"->18)
如果想从—个空的映射开始,你需要选定一个映射实现并给出类型参数:
val personAges1 =new scala.collection.mutable.HashMap [String, Int]
在Scala中,映射是对偶的集合。对偶简单地说就是两个值构成的组,这两个值并不一定是同一个类型的,比如("Alice",10)
获取Map中的值
- 方式1
println("Alice=> " + personAges.get("Alice111"))
类似于Java中的personAges.get("Alice111"),如果映射并不包含请求中使用的键,则会抛出异常。要检查映射中是否有某个指定的键,可以用contains方法。
- 方式2:contains方法
val personAlice = if (personAges.contains ("Alice")) { personAges("Alice") }else 0
println("personAlice===> " + personAlice)
- 方式3
println("Alice1.else=> " + personAges.getOrElse("Alice",0)) // 如果映射包含键“Alice",返回对应的值;否则,返回0
最后,映射.get(键)这样的调用返回一个Option对象,要么是Some(键对应的值),要么是None,Option对象有get函数,直接调用即可获取原来Map中key所对应的value
更新Map中的值
1、更新可变映射
在可变映射中,你可以更新某个映射的值,或者添加一个新的映射关系,做法是在=号的左侧使用():
personAges("Job") = 31 // 更新键"Job"对应的值
personAges("Garry") = 27 // 增加新的键/值对偶到personAges
或者,你也可以用+=操作来添加多个关系:
personAges += ("Bob"-> 10, "Fred"->7)
要移除某个键和对应的值,使用-=操作符:
personAges -="Alice"
2、更新不可变映射
虽然不能更新一个不可变的映射,但你可以做一些同样有用的操作,即获取一个包含所需要的更新的新映射
val personAges = Map("Alice" -> 20, "Job" -> 28, "Garry" -> 18)
val newPersonAges = personAges + ("Job" -> 10,"Fred" -> 7) // 更新过的新映射
println("newPersonAges=> " + newPersonAges)
同时也可以声明var变量
var personA = Map("Alice"-> 20, "Job"->28, "Garry"->18)
personA = personA + ("Bob"->10, "Fred"->7)
println("personA=> " +personA)
同时移除不可变映射的值
personA = personA -"Alice" // 其实也相当于是重新创建了一个新的Map对象
println("remove.personA => "+ personA)
遍历Map
val personAges = Map ("Alice"-> 20, "Job"->28, "Garry"->18)
for ((k,v) <- personAges) print("k=> " + k +"\t v=> " + v +" ") println() // 同时获取key和value
for((k,_)<- personAges) print("k => " + k +" ") println() // 只获取key
for(k <- personAges.keySet) print("kkkk=> " + k +" ") println() // 只获取key
for((_,v) <- personAges) print("v=> " + v +" ") println() // 只获取value
for ( v <- personAges.values) print("vvvv=> " + v) // 只获取value
scala> person.foreach(me => println(me._1)) // 只获取key,通过元组的方式
jieling
xiaoqiutian
xpleaf
scala> person.foreach(me => println(me._2)) // 只获取value,通过元组的方式
22
17
23
要反转一个映射,即交换键和值的位置,可以用:
for ( (k,v) <- personAges) yield print(v,k)
scala> for((k,v) <- person) yield print(v, k)
(22,jieling)(17,xiaoqiutian)(23,xpleaf)res177: scala.collection.mutable.Iterable[Unit] = ArrayBuffer((), (), ())
scala> for((k,v) <- person) yield(v, k) // 应该是这样才对,因为上面的方式值为空的
res178: scala.collection.mutable.Map[Int,String] = Map(23 -> xpleaf, 17 -> xiaoqiutian, 22 -> jieling)
Map排序
val personAges = scala.collection.immutable.SortedMap("Alice"->10,"Fred"->7,"Bob"->3,"Cindy"->8) // 会按照key的字典顺序进行排序
println("personAges==> " + personAges) // personAges==> Map(Alice -> 10, Bob -> 3, Cindy -> 8, Fred -> 7)
val months = scala.collection.mutable.LinkedHashMap("January" -> 1,"February" -> 2,"March" -> 3) // 创建一个顺序的Map
months += ("Fourth" -> 4)
println("months=> " + months) // months=> Map(January -> 1, February -> 2, March -> 3, Fourth -> 4)
tuple
元组定义
映射是键/值对偶的集合。对偶是元组( tuple)的最简单形态,元组是不同类型的值的聚集。元组的值是通过将单个的值包含在圆括号中构成的。例如:
(1, 3.14, "Fred")
是一个元组,类型为:
Tuple3 [Int, Double, java.lang.String]
下面是元组简单的定义方式:
val t = (1,3.14, "John")
println(t._1 +"\t " + t._2 +"\t " + t._3)
需要注意的是:和数组或字符串中的位置不同,元组的各组元从1开始,而不是0。你可以把t._2写为t _2,即用空格而不是句点,但不能写成t_2
当然也可以通过下面的方式进行定义:
scala> val tuple = new Tuple4[String, Int, String, Double]("xpleaf", 1, "guangdong", 17000)
tuple: (String, Int, String, Double) = (xpleaf,1,guangdong,17000.0)
获取元组
val t = (1, 3.14, "John", "Garry")
println(t._1 +"\t " + t._2 +"\t " + t._3 + "\t" + t._4)
val (first,second,third,fourth) = t // 这种赋值方式与Python是一样的,通过元组赋值给多个值
println(first + "\t" + second + "\t" + third + "\t" + fourth)
println("New York".partition ( _.isUpper)) // (NY,ew ork)
遍历元素:
t.productIterator.foreach(x => print(x +" "))
另外有需要云服务器可以了解下创新互联scvps.cn,海内外云服务器15元起步,三天无理由+7*72小时售后在线,公司持有idc许可证,提供“云服务器、裸金属服务器、高防服务器、香港服务器、美国服务器、虚拟主机、免备案服务器”等云主机租用服务以及企业上云的综合解决方案,具有“安全稳定、简单易用、服务可用性高、性价比高”等特点与优势,专为企业上云打造定制,能够满足用户丰富、多元化的应用场景需求。
分享题目:Scala笔记整理(二):Scala数据结构—数组、map与tuple-创新互联
当前URL:http://cdiso.cn/article/djioic.html