数组和集合(一)

Kotlin为数组增加了一个Array 类,为元素是基本类型的数组增加了 XxxArray 类(其中 Xxx 可以是 Byte、Short、 Int 等基本类型),因此开发者完全可用面向对象的语法来使用 Kotlin 的数组,包括创建数组对象、调用数组对象的属性和方法等 。
Kotlin 自己提供了一套集合体系, Kotlin 的集合体系抛弃了 Java集合体系中的 Queue集合, 但增加了可变集合和不可变集合的概念 。 Kotlin 的集合体系由三种集合组成,如图所示 :


A2AFAFC8-6406-4854-A10F-FD44E0AE31D0.png

与 Java 集合类似的是,Kotlin的ist代表着有序,集合元素可重复的集合,Set代表着无序、集合元素不可重复的集合; Map 则采用 key-value 对的形式存储数据,每项数据都由 key-value 对组成 。

数组

Kotlin 的数组使用 Array<T>类代表,由此可见,Kotlin数组就是一个 Array类的实例,因此 Kotlin数组当然也算引用类型了。

创建数组

Kotlin 创建数组其实就是创建 Array<T>类的实例, Kotlin 既可允许通过 Array<T>类的构造器来创建实例,也可通过 arrayOf()等工具函数来创建实例。
Kotlin 创建数组大致有如下两种方式。

  • 使用 arrayOf()、 arrayOfNulls()、 emptyArray()工具函数。
  • 使用 Array(size: Int, init: (Int) -> T)构造器。
fun main(args: Array<String>) {
    //创建包含指定元素的数组(相当于 Java 数组的静态初始化〉
    var arr1 = arrayOf("c", "c#", "c++")
    var intArr1 = arrayOf(2, 3, 4, 6, 7, 8)
    //创建指定长度、元素为 null 的数组(相当于 Java 数组的动态初始化)
    var arr2 = arrayOfNulls<Double>(5)
    var intArr2 = arrayOfNulls<Int>(6)
    //创建长度为 0 的空数组
    var arr3 = emptyArray<String>()
    var intArr3 = emptyArray<Int>()
    //创建指定长度、使用 Lambda 表达式初始化数组元素的数组
    var arr4 = Array(5, { (it * 2 + 97).toChar() })
    var strArr4 = Array(6, { "css" })
    for (item in strArr4) {
        println(item)
    }
}
  1. 使用 arrayOf()函数:这种方式无须显式指定数组的长度,但需要依次列出每个数组元素。因此,这种方式其实就相当于 Java数组的静态初始化。使用这种方式创建数组时, 由于程序己经给出了每个数组元素,因此 Kotlin 可以推断出数组元素的类型。所以, 不需要在 arrayOf()函数上使用泛型来指定数组元素的类型。
  2. 使用 arrayOfNulls()函数:这种方式需要显式指定数组的长度,数组元素全部被初始化为null,可见这种方式就是 Java数组的动态初始化。使用这种方式创建数组时,由于 Kotlin 无法推断出数组元素的类型,所以需要在 arrayOfNulls()函数上使用泛型来指定数组元素的类型。
  3. 使用 emptyArray()函数: 这种方式会创建一个长度为 0 的空数组。由于没有指定数组元素,因此需要使用泛型来指定数组元素的类型。
  4. 使用 Array(size: Int, init: (Int) -> T)构造器: 这种方式需要显式指定数组的长度,并可通过 Lambda表达式来动态计算各数组元素的值。这种方式是原来 Java所不具备的。

此外,由于 Array<T>类要求它的元素必须是引用类型,因此,如果程序将基本类型的值存入 Array<T>中, Kotlin 会将这些基本类型的值自动装箱成包装类的实例,然后才将这些实例添加到 Array<T>数组中。为此, Kotlin 专门提供了 ByteArray、ShortArray、IntArray、LongArray、 CharArray、FloatArray、DoubleArray、BooleanArray,分别用于映射 Java的 byte[]、short[]、int[]、 long[]、 char[]、 float[]、 double[]、 boolean[]这 8 种基本类型的数组。
创建 XxxArray 对象的方式与前面介绍的方式大致相同 。例如:

fun main(args: Array<String>) {
    //创建包含指定元素的数组(相当于 Java 数组的静态初始化)
    var intArr1 = intArrayOf(1, 2, 3)
    var doubleArr1 = doubleArrayOf(1.1, 2.3, 4.5)
    //创建指定长度、使用 Lambda表达式初始化数组元素的数组
    var intArr2 = IntArray(5, { it * it })
    var charArray = CharArray(4, { (it * 2 + 97).toChar() })
    //输出[0, 1, 4, 9, 16]
    println(Arrays.toString(intArr2))
}

从上面代码可以看出,对于 XxxArray数组,同样可采用列出数组元素(静态初始化)的方式来创建数组,但不支持使用将元素初始化为 null 的方式来创建数组,这是因为基本类型的元素不允许为 null。

使用数组

数组的常用方法就是访问数组元素,包括对数组元素进行赋值和取出数组元素的值。访问数组元素都是通过在数组引用变量后紧跟一个方括号([])实现的,方括号里是数组元素的索引值,正如前面所介绍的, Kotiin 的方括号运算符其实是 get(index)和 set(index, value)方法, 因此当程序使用[i]获取数组元素的值时,实际上就是调用 get(index)方法;当使用 [index]对数组元素赋值时,实际上就是调用 set(index,value)方法。

fun main(args: Array<String>) {
    //创建包含指定元素的数组(相当于 Java 数组的静态初始化)
    var intArr1 = intArrayOf(1, 2, 3)
    println(intArr1[1])
    println(intArr1.get(1))
    intArr1.set(0,10)
    intArr1.set(1,20)
    println(Arrays.toString(intArr1))
}
fun main(args: Array<String>) {
    //创建包含指定元素的数组(相当于 Java 数组的静态初始化)
    var intArr1 = intArrayOf(1, 2, 3)
    println(intArr1[1])
    println(intArr1.get(1))
    intArr1.set(0, 10)
    intArr1.set(1, 20)
    println(Arrays.toString(intArr1))
    //通过得到数组的size,遍历数组
    for (i in 0 until intArr1.size) {
        println(intArr1[i])
    }
    //for-in循环遍历数组
    for (item in intArr1) {
        println(item)

    }
    //使用数组索引遍历
    for (i in intArr1.indices){
        println(intArr1[i])
    }

    //判断是否在索引的区间内
    println(1 in intArr1.indices)
}

数组的常用方法

fun main(args: Array<String>) {
    //定义一个数组
    var intArr1 = arrayOf(1, 4, 5, 6)
    //判断所有数的平方是不是都大于20
    println(intArr1.all({ it * it > 20 }))
    //判断是否有一元素的平方大于 20
    println(intArr1.any({ it * it > 20 }))
    //根据数组元素来计算< K, V>对,返回所有< K, V>对组成的 Map 集合
    // 下面的算法规则是: K 是数组元素+ 10, v 是数组元素的平方
    println(intArr1.associate({ it + 10 to it * it }))
    //创建一个可变 Map 集合,用于追加根据数组计算出来的 key-value 对
    var map = mutableMapOf(1 to 100, 2 to 120, -1 to 130)
    //将计算出来的 key (元素的平方)、 value (元素)对添加到 map 集合中
    intArr1.associateByTo(map, { it * it })
    println(map)
    //计算数组所有元素的总和
    println(intArr1.fold(0, { acc, e -> acc + e }))

    //定义一个 a 数组
    var a = arrayOf(3, 4, 5, 6)
    //定义一个 a2 数组
    var a2 = arrayOf(3, 4, 5, 6)
    // a 数组和 a2 数组的长度相等,每个元素依次相等 , 将输出 true
    println("a 数组和 a2 数组是否相等:${a.contentEquals(a2)}")
    //通过复制 a 数组,生成一个新的 b 数组
    var b = a.copyOf(6)
    println("a 数组和 b 数组是否相等:${a.contentEquals(b)}")
    //输出b数组
    println(Arrays.toString(b))
    println(b.contentToString())
    //计算两个集合的并集
    println((b + a).contentToString())
}

多维数组

所谓的多维数组其实都是一维数组,只要让数组的元素又是数组,那么该数组就变成了多维数组 。

fun main(args: Array<String>) {
    //定义二维数组
    var arr1 = arrayOfNulls<Array<Int>>(4)
    //同时初始化二维数组的两个维数
    var b = Array<IntArray>(3 , {IntArray(4 , {0}) })
    for (i in arr1.indices){
        println(arr1[i])
    }
    //初始化 arr1 数组的第一个元素
    arr1[0] = arrayOf(1,2,3)
    //访问 arr1数组的第一个元素所指数组的第二个元素
    arr1[0]?.set(1,6)
    //arr1数组的第一个元素是一个一维数组, 遍历这个一维数组
    for (i in arr1[0]!!.indices){
        println(arr1[0]!![i])
    }
}

Kotlin 集合概述

Kotlin 的集合类同样由两个接口派生: Collection 和 Map。 Collection 和 Map是Java 集合框架的根接口,这两个接口又包含了一些子接口或实现类 。Kotlin 集合与 Java 集合不同, Java 集合都是可变集合,开发者可以向集合中添加、删除、修改元素,但 Kotlin 的集合被分成两大类 : 可变集合和不可变集合。只有可变集合才能添加、删除、修改元素,不可变集合只能读取元素。

纵观 Kotiin 集合体系,不难发现 Kotlin 只提供了 HashSet、 HashMap、 LinkedHashSet、LinkedHashMap、 ArrayList这5个集合实现类,而且它们都是可变集合。那么说好的不可变集合呢? Kotlin 的不可变集合类并没有暴露出来,我们只能通过函数来创建不可变集合。

Set集合

实际上 Kotlin并没有真正为JVM平台实现任何 Set集合类(只是通过别名借用了Java集合框架的类),因此不推荐通过构造器创建 Set 集合,而是推荐使用 Kotlin 提供的工具函数来创建Set集合。
Kotlin提供了如下函数来创建 Set集合。

  1. setOf(): 该函数返回不可变的 Set 集合。该函数可接受 0 个或多个参数,这些参数将作为集合的元素。保证元素的顺序。
  2. mutableSetOf(): 该函数返回可变的 MutableSet 集合。该函数可接受 0 个或多个参数, 这些参数将作为集合的元素。
  3. hashSetOf(): 该函数返回可变的 HashSet 集合。该函数可接受0个或多个参数,这些参数将作为集合的元素。
  4. linkedSetOf():该函数返回可变的 LinkedHashSet集合。该函数可接受 0个或多个参数,这些参数将作为集合的元素。
  5. sortedSetOf():该函数返回可变的 TreeSet集合 。该函数可接受 0个或多个参数,这些参数将作为集合的元素 。

如下程序示范了使用工具函数创建 Set集合。

fun main(args: Array<String>) {
    //创建不可变集合,返回值是Set
    var set1: Set<String> = setOf<String>("java", "c", "c#", "c++")
    //保证元素的顺序
    println(set1)
    //创建可变集合,返回值是 MutableSet
    var set2 = mutableSetOf<String>("java", "c", "c#", "c++")
    println(set2) //集合元素按添加顺序排列
    println("setOf 的返问对象的实际类型:${set1.javaClass} ")
    println("mutableSetOf 的返回对象的实际类型 :${set2.javaClass}")

    ////创建 HashSet 集合
    var set3 = hashSetOf<String>("java", "c", "c#", "c++")
    println(set3) //不保证元素的顺序
    //创建 LinkedHashSet 集合
    var set4 = linkedSetOf<String>("java", "c", "c#", "c++")
    println(set4) //集合元素按添加顺序排列
    //创始 TreeSet 集合
    var set5 = sortedSetOf("java", "c", "c#", "c++")
    println(set5) //集合元索由小到大排列
}

注意:Set不是无序集合,实际上,Set 只是一个接口,而该接口下常用的 3 个实现类,HashSet、 LinkedHashSet 和 TreeSet 中有两个是有序的。

使用set的方法

fun main(args: Array<String>) {
    //创建不可变集合,返回值是Set
    var set1: Set<String> = setOf<String>("java", "c", "c#", "c++", "kotlin")
    //判断是否所有元素的长度都大于 4
    println(set1.all({ it.length > 4 }))
    //判断是否任一元素的长度都大于 4
    println(set1.any({ it.length > 4 }))
    //以 Lambda 表达式的值为 key,集合元素为 value,组成 Map 集合
    val map = set1.associateBy({ "我想学" + it })
    //{我想学java=java, 我想学c=c, 我想学c#=c#, 我想学c++=c++, 我想学kotlin=kotlin}
    println(map)
    //由于有 contains ()方法,所以可用 in、! in 运算符
    println("java" in set1)
    //返回删除 Set 集合前里两个元素后的集合
    val dropList = set1.drop(2)
    println(dropList)
    //对 Set 集合元素进行过滤:要求集合元素包含 li
    val filteredList = set1.filter { "li" in it }
    println(filteredList)
    //查找 Set 集合中包含 li的元素,如果找到就返回该元素,否则返回 null
    val foundStr1 = set1.find { "li" in it }
    println(foundStr1)
    //将 Set 集合中的所有字符串拼接在一起
    val foldedList = set1.fold("", { acc, e -> acc + e })
    //javacc#c++kotlin
    println(foldedList)
    //查找某个元素的出现位置
    println(set1.indexOf("java"))
    //将每个集合元素映射成新值,返回所有新值组成的 Set 集合
    val mappedList = set1.map { "不想学" + it }
    //[不想学java, 不想学c, 不想学c#, 不想学c++, 不想学kotlin]
    println(mappedList)
    //获取最大值
    println (set1.max())
    //反转集合顺序
    val reversedList = set1.reversed()
    println(reversedList)
    var bSet = setOf("android",".net","php","kotlin")
    //计算两个集合的交集
    println(set1 intersect bSet)
    //计算两个集合的并集
    println(set1 union bSet)
    //集合相加,相当于并集
    println(set1 + bSet)
    //集合相减,减去它们公共的元素
    println(set1 - bSet)
}

遍历Set

fun main(args: Array<String>) {
    //创建不可变集合,返回值是Set
    var set1: Set<String> = setOf<String>("java", "c", "c#", "c++", "kotlin")
    //for-in遍历
   for (item in set1){
       println(item)
   }

    //调用 forEach 方法来遍历 Set 集合
    set1.forEach { println(it) }
    //由于 setOf()方法返回的 Set集合是有序的,因此可以通过索引来遍历 Set集合
    for (i in set1.indices){
        println(set1.elementAt(i))
    }
}

可变的Set

除使用 setOf()函数返回的集合是不可变集合之外,使用 mutableSetOf()、 hashSetOf()、 linkedSetOf()、 sortedSetOf()函数返回的集合都是可变的,其中后面三个函数返回的集合类型都是明确的,依次是 HashSet、 LinkedHashSet、 TreeSet。

  1. 添加元素
fun main(args: Array<String>) {
    //创建可变集合,返回值是MutableSet
    var set1: MutableSet<String> = mutableSetOf("java", "c", "c#", "c++", "kotlin")
    set1.add("111")
    set1.addAll(setOf("22","333"))
}
  1. 删除元素
fun main(args: Array<String>) {
    //创建可变集合,返回值是MutableSet
    var set1: MutableSet<String> = mutableSetOf("java", "c", "c#", "c++", "kotlin")
    set1.remove("c")
    set1.removeAll(setOf("java","kotlin"))
    println(set1)
    //只保留 Set集合中与 elements 集合共有的元素
    set1.retainAll(setOf("c#","oc"))
    println(set1)
    //清空集合
    set1.clear()
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容