[转] Scala 的集合类型与数组操做

[From] https://blog.csdn.net/gongxifacai_believe/article/details/81916659html

 

 

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/gongxifacai_believe/article/details/81916659

一、Scala中的集合

Scala有一个很是通用丰富强大可组合的集合库;集合是高阶的,并拥有一大套操做方法。Scala的全部的集合类均可以在包 scala.collection 包中找到,其中集合类都是高级抽象类或特性。

Iterable[T] 是全部可遍历的集合,它提供了迭代的方法(foreach)。
Seq[T] 是有序集合。
Set[T]是数学上的集合(无序且不重复)。
Map[T]是关联数组,也是无序的。
Scala 集合类系统地区分了可变的和不可变的集合。
可变集合能够在适当的地方被更新或扩展,意味着你能够修改、添加、移除一个集合的元素。而不可变集合类,相比之下永远不会改变。不过,你仍然能够模拟添加移除或更新操做。可是这些操做将在每一种状况下都返回一个新的集合,同时使原来的集合不发生改变。可变的集合类位于 scala.collection.mutable 包中,而不可变的集合位于 scala.collection.immutable.scala.collection 包中。集合既能够是可变的,也能够是不可变的。
官方文档:http://www.scala-lang.org/docu/files/collections-api/collections.html
全部集合组件图示以下:
算法

 

二、Scala集合List和Set

Scala集合中的seq包含了:Range和ArrayBuffer以及List。这些组件区分了可变和不可变类型。
(1)建立list集合编程

val list = List(1,2,3,4,5)

(2)Scala中的list包含两个部分,head+tail或head+Nil
list.head 表明返回第一个元素,list.tail 表明返回一个不包含第一个元素的集合,Nil表明空的list集合。api

val list2 = 1::Nil

注意集合的顺序,前面是元素后面是集合数组

val list3 = 2::list2

前面的元素就是新的list的head,后面的就是新的list的tail
(3)建立一个可变的list集合markdown

val listBuffer = scala.collection.mutable.ListBufferInt

(4)添加元素函数式编程

listBuffer += 2
listBuffer +=(3,4,5)
listBuffer ++= List(6,7,8)
listBuffer -= (4,7)

(5)list练习:指定前缀
需求:使用递归函数给list中的每一个元素都加上指定的前缀,而且打印出加上前缀的元素。
注意:最后一个元素的时候它的tail就是Nil。函数

def dtor(list: List[Int], pfix: String){
    if(list != Nil){
        println(pfix + list.head)
        dtor(list.tail,pfix)
    }
 }

(6)set集合建立
不可变集合:post

val set = Set(1,2,3,4)

可变集合:性能

val s = scala.collection.mutable.Set(1,2)

添加元素:
不可变集合:+ ++ - –
可变集合:+= ++= -= --=

 

三、Scala集合Map与Tuple

(1)建立Map
建立一个不可变的Map:

val ages = Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
ages(“Leo”) = 31

建立一个可变的Map:

val ages = scala.collection.mutable.Map(“Leo” -> 30, “Jen” -> 25, “Jack” -> 23)
ages(“Leo”) = 31

使用另一种方式定义Map元素:

val ages = Map((“Leo”, 30), (“Jen”, 25), (“Jack”, 23))

建立一个空的HashMap:

val ages = new scala.collection.mutable.HashMap[String, Int]

(2)访问Map的元素
获取指定key对应的value,若是key不存在,会报错:

val leoAge = ages(“Leo”)
val leoAge = ages(“leo”)

使用contains函数检查key是否存在:

val leoAge = if (ages.contains(“leo”)) ages(“leo”) else 0

getOrElse函数:

val leoAge = ages.getOrElse(“leo”, 0)

(3)修改Map的元素
更新Map的元素:

ages(“Leo”) = 31

增长多个元素:

ages += (“Mike” -> 35, “Tom” -> 40)

移除元素:

ages -= “Mike”

更新不可变的map:

val ages2 = ages + (“Mike” -> 36, “Tom” -> 40)

移除不可变map的元素:

val ages3 = ages - “Tom”

(4)遍历Map
遍历map的entrySet:

for ((key, value) <- ages) println(key + ” ” + value)

遍历map的key:

for (key <- ages.keySet) println(key)

遍历map的value:

for (value <- ages.values) println(value)

生成新map,反转key和value:

for ((key, value) <- ages) yield (value, key)

(5)SortedMap和LinkedHashMap
SortedMap能够自动对Map的key的排序:

val ages = scala.collection.immutable.SortedMap(“leo” -> 30, “alice” -> 15, “jen” -> 25)

LinkedHashMap能够记住插入entry的顺序:

val ages = new scala.collection.mutable.LinkedHashMap[String, Int]
ages(“leo”) = 30
ages(“alice”) = 15
ages(“jen”) = 25

(6)Map的元素类型—Tuple
Map的每个元素(key,value)就称做:tuple元组对
简单的Tuple定义:

val t = (“leo”, 30)

访问Tuple:

t._1

zip拉链操做:

val names = Array(“leo”, “jack”, “mike”)
val ages = Array(30, 24, 26)
val nameAges = names.zip(ages)
for ((name, age) <- nameAges) println(name + “: ” + age)

 

四、数组Array

在Scala中,Array表明的含义与Java中相似,也是长度不可改变的数组。此外,因为Scala与Java都是运行在JVM中,双方能够互相调用,所以Scala数组的底层其实是Java数组。例如字符串数组在底层就是Java的String[],整数数组在底层就是Java的Int[]。
(1)数组初始化后,长度就固定下来了,并且元素所有根据其类型初始化

val a = new ArrayInt
a(0)
a(0) = 1
val a = new ArrayString

(2)能够直接使用Array()建立数组,元素类型自动推断

val a = Array(“hello”, “world”)
a(0) = “hi”
val a = Array(“leo”, 30)

(3)数组元素求和

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

(4)获取数组最大值

val max = a.max

(5)对数组进行排序

scala.util.Sorting.quickSort(a)

(6)获取数组中全部元素内容

a.mkString
a.mkString(“, “)
a.mkString(“<”, “,”, “>”)

(7)toString函数

a.toString

 

五、数组ArrayBuffer

在Scala中,若是须要相似于Java中的ArrayList这种长度可变的集合类,则可使用ArrayBuffer。
(1)若是不想每次都使用全限定名,则能够预先导入ArrayBuffer类

import scala.collection.mutable.ArrayBuffer

(2)使用ArrayBuffer()的方式能够建立一个空的ArrayBuffer

val b = ArrayBufferInt

(3)使用+=操做符,能够添加一个元素,或者多个元素。这个语法必需要谨记在心!由于spark源码里大量使用了这种集合操做语法!

b += 1
b += (2, 3, 4, 5)

(4)使用++=操做符,能够添加其余集合中的全部元素

b ++= Array(6, 7, 8, 9, 10)

(5)使用trimEnd()函数,能够从尾部截断指定个数的元素

b.trimEnd(5)

(6)使用insert()函数能够在指定位置插入元素,可是这种操做效率很低,由于须要移动指定位置后的全部元素。

b.insert(5, 6)
b.insert(6, 7, 8, 9, 10)

(7)使用remove()函数能够移除指定位置的元素

b.remove(1)
b.remove(1, 3)

(8)Array与ArrayBuffer能够互相进行转换

b.toArray
a.toBuffer

(9)使用for循环和until遍历Array / ArrayBuffer
until是RichInt提供的函数

for (i <- 0 until b.length)
println(b(i))

(10)跳跃遍历Array / ArrayBuffer

for(i <- 0 until (b.length, 2))
println(b(i))

(11)从尾部遍历Array / ArrayBuffer

for(i <- (0 until b.length).reverse)
println(b(i))

(12)使用“加强for循环”遍历Array / ArrayBuffer

for (e <- b)
println(e)

(13)toString函数

b.toString

 

六、数组操做

(1)使用yield和函数式编程转换数组
对Array进行转换,获取的仍是Array

val a = Array(1, 2, 3, 4, 5)
val a2 = for (ele <- a) yield ele * ele

对ArrayBuffer进行转换,获取的仍是ArrayBuffer

val b = ArrayBufferInt
b += (1, 2, 3, 4, 5)
val b2 = for (ele <- b) yield ele * ele

结合if守卫,仅转换须要的元素

val a3 = for (ele <- if ele % 2 == 0) yield ele * ele

(2)使用函数式编程转换数组(一般使用第一种方式)

a.filter(_ % 2 == 0).map(2 * _)
a.filter { _ % 2 == 0 } map { 2 * _ }

(3)算法案例:移除第一个负数以后的全部负数

  1.   算法一:
    构建数组:
val a = ArrayBufferInt
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)

每发现一个第一个负数以后的负数,就进行移除,性能较差,屡次移动数组:

var foundFirstNegative = false
var arrayLength = a.length
var index = 0
while (index < arrayLength) {
	if (a(index) >= 0) {
		index += 1
	} else {
	if (!foundFirstNegative) { foundFirstNegative = true; index += 1 }
	else { a.remove(index); arrayLength -= 1 }
	}
}

2.  算法二:
从新构建数组:

val a = ArrayBufferInt
a += (1, 2, 3, 4, 5, -1, -3, -5, -9)

每记录全部不须要移除的元素的索引,稍后一次性移除全部须要移除的元素。该算法性能较高,数组内的元素迁移只要执行一次便可。

var foundFirstNegative = false
val keepIndexes = for (i <- 0 until a.length if !foundFirstNegative || a(i) >= 0) yield {
	if (a(i) < 0) foundFirstNegative = true
	i
}
for (i <- 0 until keepIndexes.length) { a(i) = a(keepIndexes(i)) }
a.trimEnd(a.length - keepIndexes.length)