scala学习笔记
@TOC
前言
Scala的提供的集合有三大类: 序列Seq、集Set、映射Map。 这些三类又衍生出很多子类,这些集合的特点一时很难全部了解和掌握,我们只能从一些常用的开始,在日后的工作中如果需要再去深入了解。 每个集合类型都包含了大量方法,这些方法能让我们的工作更轻松,但同样我们也不比记住每一个方法,可以先从一些常用的方法开始,去解决实际的问题,循序渐进。
一、不可变集合&&可变集合
所有的集合都扩展自Iterable特质,在Scala中集合都有可变(mutable)和不可变(immutable)两种类型。对应两个重要的包: 不可变集合:scala.collection.immutable 可变集合: scala.collection.mutable 1.scala不可变集合,就是这个 集合本身不能动态变化。长度一旦确定就没法修改,增删元素只能把结果赋给新的一个集合,集合本身不会发生改变,但可以修改里面的元素的值。 2.可变集合就是这个 集合本身可以动态变化的,增加或删减都可以基于这个集合本身操作。
scala集合继承关系图,这些都是高级的抽象类或者特质
不可变集合继承结构图:
可以看到Set,Map,Seq全部扩展自Iterable特质. Set集合有包含了HashSet,SortedSet(又包含TreeSet),BitSet,ListSet Map集合有包含了HashMap,SortedMap(又包含TreeMap),ListMap Seq集合有主要分为indexedSeq(索引序列)和linearSeq(线性序列),地下又有所细分。
可变结合继承结构图
整体结构差不多,但是内容更丰富,序列中多了Buffer,常用的如ArrayBuffer和ListBuffer。涉及线程安全的用syn开头的结构。 总结et、Map是Java中也有的集合
- Seq是Java没有的,List归属到Seq了,所以这里的List就和java不是同一个概念了
- String也是属于IndexeSeq
- 我们发现经典的数据结构比如Queue 和 Stack被归属到LinearSeq
- Scala中的Map体系有一个SortedMap,说明Scala的Map可以支持 排序
- IndexSeq 和 LinearSeq 的区别[IndexSeq是通过索引来查找和定位, 因此速度快,比如String就是一个索引集合,通过索引即可定位][LineaSeq 是线型的,即有头尾的概念,这种数据结构一般是通过遍历来查找。
二、Sequences(序列)
Seq序列是元素的顺序集合,可以是索引的(如数组)或线性的(如链表)。 当我们选择一个序列时,需要决定两点 1.序列应该被索引(像数组一样) ,允许快速访问任何元素,还是应该实现为线性链表。 2.是需要一个可变的还是不可变的集合?
项目 | 不可变 | 可变 |
---|---|---|
索引 | Vector、Array | ArrayBuffer |
线性 | List | ListBuffer |
List
1.创建一个list
val ints = List(1, 2, 3)
//结果:List(1, 2, 3)
val names = List("Joel", "Chris", "Ed")
//结果:List(Joel, Chris, Ed)
// another way to construct a List
val namesAgain = "Joel" :: "Chris" :: "Ed" :: Nil
//结果:List(Joel, Chris, Ed)
可以在创建指定类型
//List[Int]限定元素只能为Int
val ints: List[Int] = List(1, 2, 3)
//List[String]限定元素只能为String
val names: List[String] = List("Joel", "Chris", "Ed")
//混合类型,这时候最好指定类型
val things: List[Any] = List("Joel", "Chris", "Ed",1,5.0)
2.增:
//单元素添加 ::
val new_name= "james" :: names
//结果:List(james, Joel, Chris, Ed)
//val new_name3= names :: "james" 这种添加是错误的。只能往前加,因为是List是单链表
//两个List合并,三冒号 :::
val new_name2= List("james","lbj") ::: names
//结果:List(james, lbj, Joel, Chris, Ed)
+:& :+ 看着有点乱,有个办法方便记忆,冒号:代表序列所在的那一边
val names = List("Joel", "Chris", "Ed")
val new_name3= "polo" +: names
val new_name4= names :+ "polo"
println(new_name3)
//List(polo, Joel, Chris, Ed)
println(new_name4)
//List(Joel, Chris, Ed, polo)
查:
val names2= "Joel" :: "Chris" :: "Ed" :: Nil
println(names2(2))
//结果:Ed
因为 List 是一个链表,所以不应该尝试通过索引值访问大型列表的元素。例如,如果 List 中有100万个元素,访问 myList (999 _ 999)这样的元素将花费相对较长的时间,因为该请求必须遍历所有这些元素。如果您有一个大型集合,并且希望通过索引访问元素,那么可以使用 Vector 或 ArrayBuffer。
遍历: 使用 for 循环的一个好处是 Scala 是一致的,同样的方法适用于所有序列,包括 Array、 ArrayBuffer、 List、 Seq、 Vector、 Map、 Set 等。
for(name <- names)
println(name)
2.Vector
Vector 是一个有索引的、不可变的序列。“索引”意味着它提供了的随机访问和更新,不需要遍历整个列表,因此可以通过它们的索引值快速访问 Vector 元素. 1.创建
val nums = Vector(1, 2, 3, 4, 5)
val strings = Vector("one", "two")
case class Person(name: String)
val people = Vector(
Person("Bert"),
Person("Ernie"),
Person("Grover")
)
2.增 不可变,所以不能再原来的vector增加,只能创建一个新得
//末尾追加
val a = Vector(1,2,3) // Vector(1, 2, 3)
val b = a :+ 4 // Vector(1, 2, 3, 4)
val c = a ++ Vector(4, 5) // Vector(1, 2, 3, 4, 5)
//队前追加
val a = Vector(1,2,3) // Vector(1, 2, 3)
val b = 0 +: a // Vector(0, 1, 2, 3)
val c = Vector(-1, 0) ++: a // Vector(-1, 0, 1, 2, 3)
3.ArrayBuffer
常用的可变seq有ArrayBuffer,ListBuffer 重点介绍一下ArrayBuffer。 1.创建
//导入包
import scala.collection.mutable.ArrayBuffer
//带类型的ArrayBuffer
var strings = ArrayBuffer[String]()
var ints = ArrayBuffer[Int]()
var people = ArrayBuffer[Person]()
//指定初始长度核类型
// ready to hold 100,000 ints
val buf = new ArrayBuffer[Int](100_000)
//初始元素
val nums = ArrayBuffer(1, 2, 3)
val people = ArrayBuffer(
Person("Bert"),
Person("Ernie"),
Person("Grover")
)
2.增加元素: 符号函数:+=&++= 名称函数:队尾(append, appendAll),队中( insert, insertAll), 队头(prepend, and prependAll)
val nums = ArrayBuffer(1, 2, 3) // ArrayBuffer(1, 2, 3)
nums += 4 // ArrayBuffer(1, 2, 3, 4)
nums ++= List(5, 6) // ArrayBuffer(1, 2, 3, 4, 5, 6)
3.删 符号函数:-=&--= 名称函数:clear, remove
val a = ArrayBuffer.range('a', 'h') // ArrayBuffer(a, b, c, d, e, f, g)
a -= 'a' // ArrayBuffer(b, c, d, e, f, g)
a --= Seq('b', 'c') // ArrayBuffer(d, e, f, g)
a --= Set('d', 'e') // ArrayBuffer(f, g)
4.改
val a = ArrayBuffer.range(1,5) // ArrayBuffer(1, 2, 3, 4)
a(2) = 50 // ArrayBuffer(1, 2, 50, 4)
a.update(0, 10) // ArrayBuffer(10, 2, 50, 4)
三、Maps
映射包含一组键/值对,如 Java Map、 Python 的字典dictionary 。同样在scala里也有可变和不可变的区分。 1.不可变Map
//创建
val states = Map(
"AK" -> "Alaska",
"AL" -> "Alabama",
"AZ" -> "Arizona"
)
查询
keys, keySet, keysIterator, for
```scala
//通过Key,查询value
val ak = states("AK") // ak: String = Alaska
val al = states("AL") // al: String = Alabama
增加: ++&+
val a = Map(1 -> "one") // a: Map(1 -> one)
val b = a + (2 -> "two") // b: Map(1 -> one, 2 -> two)
val c = b ++ Seq(
3 -> "three",
4 -> "four"
)
// c: Map(1 -> one, 2 -> two, 3 -> three, 4 -> four)
删除: --&-
val a = Map(
1 -> "one",
2 -> "two",
3 -> "three",
4 -> "four"
)
val b = a - 4 // b: Map(1 -> one, 2 -> two, 3 -> three)
val c = a - 4 - 3 // c: Map(1 -> one, 2 -> two)
改: updated or +
val a = Map(
1 -> "one",
2 -> "two",
3 -> "three"
)
val b = a.updated(3, "THREE!") // b: Map(1 -> one, 2 -> two, 3 -> THREE!)
val c = a + (2 -> "TWO...") // c: Map(1 -> one, 2 -> TWO..., 3 -> three)
//遍历
for (k, v) <- states do println(s"key: $k, value: $v")
//key: AK, value: Alaska
//key: AL, value: Alabama
//key: AZ, value: Arizona
有许多方法可以处理映射中的键和值。常见的 Map 方法包括 foreach、 Map、 key 和 value。 Scala 有许多专门的 Map 类型,包括 CollisionProofHashMap、 HashMap、 LinkedHashMap、 ListMap、 SortedMap、 TreeMap、 WeakHashMap 等。
四、Sets
Scala 集是一个没有重复元素的可迭代集合。 1.不可变set
//创建
val nums = Set[Int]()
val letters = Set[Char]()
//带初始值创建
val nums = Set(1, 2, 3, 3, 3) // Set(1, 2, 3)
val letters = Set('a', 'b', 'c', 'c') // Set('a', 'b', 'c')
增加: +&++
val a = Set(1, 2) // Set(1, 2)
val b = a + 3 // Set(1, 2, 3)
val c = b ++ Seq(4, 1, 5, 5) // HashSet(5, 1, 2, 3, 4)
删除 -&--
val a = Set(1, 2, 3, 4, 5) // HashSet(5, 1, 2, 3, 4)
val b = a - 5 // HashSet(1, 2, 3, 4)
val c = b -- Seq(3, 4) // HashSet(1, 2)
5.Range
Scala Range 通常用于填充数据结构,生成测试数据和迭代 for 循环。这些 REPL 示例演示了如何创建范围。 几种创建方式
1 to 5 // Range(1, 2, 3, 4, 5)
1 until 5 // Range(1, 2, 3, 4)
1 to 10 by 2 // Range(1, 3, 5, 7, 9)
'a' to 'c' // NumericRange(a, b, c)
val x = (1 to 5).toList // List(1, 2, 3, 4, 5)
val x = (1 to 5).toBuffer // ArrayBuffer(1, 2, 3, 4, 5)
Vector.range(1, 5) // Vector(1, 2, 3, 4)
List.range(1, 10, 2) // List(1, 3, 5, 7, 9)
Set.range(1, 10) // HashSet(5, 1, 6, 9, 2, 7, 3, 8, 4)
val evens = (0 to 10 by 2).toList // List(0, 2, 4, 6, 8, 10)
val odds = (1 to 10 by 2).toList // List(1, 3, 5, 7, 9)
val doubles = (1 to 5).map(_ * 2.0) // Vector(2.0, 4.0, 6.0, 8.0, 10.0)