Scala数组(三)

要点先知

  • 若长度固定,则使用Array,若长度可能 有变化则使用ArrayBuffer
  • 提供初始值时不要使用new
  • ()来访问元素
  • for(elem <- arr)来遍历元素
  • for(elem <- arr if ...)...yeild...来将原数组转型为新数组
  • Scala数据和Java数组可以互操作,用ArrayBuffer,使用scala.collection.JavaConversions中的转换函数

定长数组

val nums = new Array[Int](10) // 10个整数型的数组,所有元素初始化为0
val s = new Array[String](10) // 10个字符串类型数组,初始化为null
val s = Array("Hello", "World") // 提供初始值时不要用new
s(0) = "Goodbye"// Array("Goodbye", "World"), 使用()非[]访问元素

变长数组

import scala.collection.mutable.ArrayBuffer
val b = new ArrayBuffer[Int]() // 因为没有初始化,所以new和()可以只要一个
// val b =  ArrayBuffer[Int]() or val b = new ArrayBuffer[Int]

// 用+=给b尾端添加元素
b += 1 // ArrayBuffer(1)
b += (1, 2, 3, 5) // ArrayBuffer(1, 1, 2, 3, 5)
// 用++=追加任何集合
b ++= Array(8, 13, 21) // ArrayBuffer(1, 1, 2, 3, 5, 8, 13, 21)
// 用.trimEnd(N) 移除最后N个元素, .trimStart(N)移除开始N个元素
b.trimEnd(5) // ArrayBuffer(1, 1, 2)

在数组缓冲的尾端添加或移除元素是一个高效的操作,你也可以在任意位置添加或移除元素,但这样的操作并不那么高效,因为所有在哪个位置之后的元素都必须被平移。

// b.insert(pos, nums), 在pos位置之前插入nums
b.insert(2, 6, 7, 8) // ArrayBuffer(1, 1, 6, 7, 8, 2)
// b.remove(pos, lens = 1), 从pos位置开始,移除lens个元素
b.remove(2) // ArrayBuffer(1, 1, 7, 8, 2)
b.remove(2, 3) // ArrayBuffer(1, 1)

有时需要构建一个Array, 但不知道最终要装多少个元素。在这种情况下,先构建一个数组缓冲,然后调用:
b.toArray。然过来,调用a.toBuffer可以将一个数组a转换成一个数组缓冲。

遍历数组

  • 数组的长度:a.length
  • 遍历数据index:0 until a.length // 0 until 3, Range(0, 1, 2)
  • 遍历偶数index:0 until (a.length, 2)
  • 从尾端开始遍历:(0 until a.length).reverse

数组装换

使用for(x <- arr)yield func(x) 可以把arr数组做map函数转换

val a = Array(1, 2, 3, 4)
val result = for(elem <- a) yield 2 * elem // result = Array(2, 4, 6, 8)
// 效果等同:val result = a.map(2 * _) // _是a中元素的迭代器

常用算法

可以在Scala API文档查看Array和ArrayBuffer的常用方法

多维数组

多维数组是通过数组的数组实现的,Double的二维数组类型为Array[Array[Double]]

// 构建3行4列的矩阵
val matrix = Array.ofDim[Double](3, 4) // matrix的每个元素初始化为0.0
// 元素访问:matrix(row)(col)
matrix(0)(0) = 1

不规则数组

val triangle = new Array[Array[Int]](5) // triangle的每个元素初始化为null
for(i <- 0 until triangle.length){
    triangle(i) = new Array[Int](i + 1) // triangle(i)的每个元素初始化为0
}

与Java的互操作

Scala的数组是用Java数组实现的,所以可以在Scala和Java中来回传递。引入scala.collection.JavaConversions的隐式转换方法,这样在使用Scala缓冲,调用Java方法时,这些对象会被自动包装成Java列表。

java.lang.ProcessBuilder类中有一个以List<String>为参数的构造器。在Scala中调用它的例子:

import scala.collection.JavaConversions.bufferAsJavaList
import scala.collection.mutable.ArrayBuffer
val command = ArrayBuffer("ls", "-al", "/home/cay")
val pb = new ProcessBuilder(command) // Scala到Java的转换

Scala缓冲被包装成了一个实现了java.util.List接口的Java类对象。反过来,当Java方法返回java.util.List时,我们可以让它自动转换成一个Buffer

import scala.collection.JavaConversions.asScalaBuffer
import scala.collection.mutable.Buffer
val cmd: Buffer[String] = pd.command() // Java到Scala的转换
// 不能使用ArrayBuffer, 因为包装起来的对象仅能保证是个Buffer

练习

1. 编写一段代码,将a设置为一个n个随机整数的数组,要求随机数介于[0, n)

import scala.util.Random
val n = 10
val a = new Array[Int](n)
for(elem <- 0 until n){
    a(elem) = Random.nextInt(10)
}

2. 编写一个循环,将整数数组中相邻的数组置换。例如,Array(1, 2, 3, 4, 5)经过置换后变为Array(2, 1, 4, 3, 5)。

// 方法1
val a = Array(1, 2, 3, 4, 5)
for(i <- 0 until (a.length - 2, 2)){
    val t = a(i)
    a(i) = a(i + 1)
    a(i + 1) = t

}
// 方法2
val a = Array(1, 2, 3, 4, 5)
val result = new Array[Int](a.length)
for(i <- 0 until a.length){
    if(i == a.length - 1) {
        result(i) = a(i)
        }else if(i % 2 == 1){
            result(i) = a(i - 1)
            }else {
                result(i) = a(i + 1)
            }
}

3. 重复上一个练习,不过这一次生成一个新的值交换过的数组。用for/yield

val a = Array(1, 2, 3, 4, 5)
val result = new Array[Int](a.length)
// 先把下标置换好
val index = for(i <- 0 until a.length) yield {
     if(i == a.length - 1) {
       i
        }else if(i % 2 == 1){
            i - 1
            }else {
                i + 1
            }
        }
// 把置换好的下标给到result  
for(elem <- 0 until result.length){
    result(elem) = a(index(elem))
}

4. 给定一个整数数组,产出一个新的数组,包含原数组中的所有正值,以原有顺序排列,之后的元素是原有零或负数,以原有顺序排列。

val a = Array(1, -1, -3, 5, -5, -2, 0, 7)
val result = new ArrayBuffer[Int]()
// 两种方法: 1. 找到下标,再赋值 2. 直接赋值
// 此处只展示方法2
result ++= (for(i <- 0 until a.length if a(i) > 0) yield a(i))
result ++= (for(i <- 0 until a.length if a(i) <= 0) yield a(i))

5. 如何计算Array[Double]的平均值?

import scala.util.Random
val a = (Seq.fill(5)(Random.nextDouble * 10)).toArray // 生成5个10以内的随机double数
a.sum / a.length

6. 如何重新组织Array[Int]的元素将它们以反序排列?对于ArrayBuffer[Int]你优惠怎么做呢?

// Array, ArrayBuffer的语法一样
val a = Array(1, 2, 3, 4, 5)
val result = (for(i <- (0 until a.length).reverse) yield a(i)) // 返回的是Vector类型
// a.reverse

注:对于ArrayBuffer是否转换为Java List, 然后用Java.lang.util包的函数

7. 编写一段代码,产出数组中的所有值,去掉重复值。(提示:查看scaladoc)

val a = Array(1, 2, 3, 4, 5, 1, 1, 2, 3, 4)
a.distinct

**8. 重新编写3.4节结尾的示例。收集负值元素的下标,反序,去掉最后一个下标,然后对每一个下标调用a.remove(i)。比较这样做的效率和3.4节中另外两种方法的效率。

val a = ArrayBuffer(1, -1, -3, 5, -5, -2, 0, 7)
val result = (for(i <- 0 until a.length if a(i) < 0) yield i).reverse.dropRight(1)
for(i <- result) a.remove(i)

9. 创建一个由 java.util.TimeZone.getAvailableIDs返回的时区集合,判断条件是它们在美洲。去掉"America/"前缀并排序。

val sortedAmericanZone = java.util.TimeZone.getAvailableIDs.filter(_.startsWith("America")).map(_.replaceFirst("America/", "")).sorted
// Array、String通过filter和map等函数,结合起来无敌了

10. 引入 java.awt.datatransfer._ 并构建一个类型为 SystemFlavorMap 类型的对象: val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap] 然后以 DataFlavor.imageFlavor 为参数调用 getNativesForFlavor 方法,以 Scala 缓冲保存返回值。

import java.awt.datatransfer._
import scala.collection.JavaConversions._
import scala.collection.mutable.Buffer
val flavors = SystemFlavorMap.getDefaultFlavorMap().asInstanceOf[SystemFlavorMap]
val flavor: Buffer[String] = flavors.getNativesForFlavor(DataFlavor.imageFlavor)

参考

  1. 《快学Scala》
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容