Scala–Collections
在介绍函数式编程之前需要介绍下 Scala 的集合,以及 可变集合(mutable)、不可变集合(immutable) Scala 中的迭代的集合包括:Seq、Set、Map
集合中的可变集合(mutable):可以修改集合长度的集合。
集合中的不变集合(immutable):不可以修改集合长度的集合,集合的长度是一开始初始化就确定好的。
1. Array
1.1 不变数组–Array
定义:1) Array(
数
据
内
容
)
2
)
n
e
w
A
r
r
a
y
[
数据内容) 2) new Array [
数 据 内 容 ) 2 ) n e w A r r a y [ 数据类型] ($数据条数) 更新数据:
数
组
对
象
.
u
p
d
a
t
e
(
数组对象.update(
数 组 对 象 . u p d a t e ( 索引,$数据) Array转成一个String:
数
组
对
象
.
m
k
S
t
r
i
n
g
(
数组对象.mkString(
数 组 对 象 . m k S t r i n g ( 分隔符) 两个数组相加:$数组对象1 ++ $数组对象2 union:
数
组
1.
u
n
i
o
n
(
数组1.union(
数 组 1 . u n i o n ( 集合2) 取第一个数据:$数组.head 数组的长度:
数组中的最大、最小、总和:
数
组
.
m
a
x
、
数组.max、
数 组 . m a x 、 数组.min、$数组.sum 数组反向:$数组.reverse
1.2 可变数组–ArrayBuffer
定义:cala.collection.mutable.ArrayBuffer [$数据类型] () 插入数据:1)
数
组
.
i
n
s
e
r
t
(
数组.insert(
数 组 . i n s e r t ( 索引,
数
据
)
2
)
数据) 2)
数 据 ) 2 ) 数组 +=
数
据
3
)
数据 3)
数 据 3 ) 数组 ++= Array($数据) ArrayBuffer 转换成 Array:$可变数组.toArray 其他的都和不变数据使用差不多
package com. xk. bigdata. scala. collection
object ArrayApp {
def main( args: Array[ String ] ) : Unit = {
val array1 = new Array[ String ] ( 3 )
val array2 = Array( "hadoop2" , "spark2" , "flink2" )
array1. update( 0 , "hadoop1" )
array1. update( 1 , "spark1" )
array1. update( 2 , "flink1" )
println( array1. mkString( "," ) )
( array1 ++ array2) . foreach( println)
array1. foreach( println)
array1. union( array2) . foreach( println)
println( array1. head)
println( array1. length)
println( array1. size)
val array3 = Array( 1 , 2 , 3 , 4 , 5 , 6 )
println( array3. max)
println( array3. min)
println( array3. sum)
array1. reverse. foreach( println)
val arrayBuffer = scala. collection. mutable. ArrayBuffer[ String ] ( "hadoop" , "spark" , "flink" )
arrayBuffer. insert( 0 , "hbase" )
arrayBuffer += "spark1"
arrayBuffer ++ = Array( "hadoop1" )
arrayBuffer. update( 0 , "hbase1" )
println( arrayBuffer. toArray)
println( arrayBuffer)
}
}
2. Set
Set 特点就是:1)无序 2)去重 head 返回集合第一个元素 tail 返回一个集合,包含除了第一元素之外的其他元素 isEmpty 在集合为空时返回true 使用 Set.& 方法或 Set.intersect 方法来查看两个集合的交集元素
2.1 不变集合-Set
定义:1)Set($数据) 其他都和Array差不多
2.2 可变集合-Set
定义:scala.collection.mutable.Set($数据) 添加数据:1)
集
合
.
a
d
d
(
集合.add(
集 合 . a d d ( 数据) 2)$集合 +=
数
据
3
)
数据 3)
数 据 3 ) 集合 ++= Set($数据) 删除数据:1)
集
合
.
r
e
m
o
v
e
(
集合.remove(
集 合 . r e m o v e ( 数据) 2)$集合 -=
数
据
3
)
数据 3)
数 据 3 ) 集合 --= Set(数据)
package com. xk. bigdata. scala. collection
object SetApp {
def main( args: Array[ String ] ) : Unit = {
val set1 = Set( "spark" , "spark" , "spark1" )
val set2 = Seq( 1 , 23 , 4 , 64 , 34 )
println( set2. max)
println( set2. min)
println( set2. sum)
val set3 = scala. collection. mutable. Set( 1 , 23 , 34 )
set3. add( 2 )
set3 += 4
set3 ++ = Set( 3 , 5 , 7 )
set3. remove( 1 )
set3 -= 2
set3 -- = Set( 3 , 5 , 7 )
println( set3)
println( set3. head)
println( set3. tail)
println( set3. isEmpty)
val set4 = Set( 1 , 2 , 3 , 4 )
println( set3. intersect( set4) )
println( set3. &( set4) )
}
}
3. Tuple
元组:目前 Scala 支持的元组最大长度为 22。对于更大长度你可以使用集合,或者扩展元组。 定义:1) (
数
据
)
2
)
可
以
根
据
T
u
p
l
e
长
度
来
进
行
创
建
,
如
果
需
要
创
建
一
个
两
个
长
度
的
T
u
p
l
e
,
则
T
u
p
l
e
2
(
数据) 2)可以根据Tuple长度来进行创建,如果需要创建一个两个长度的Tuple,则 Tuple2(
数 据 ) 2 ) 可 以 根 据 T u p l e 长 度 来 进 行 创 建 , 如 果 需 要 创 建 一 个 两 个 长 度 的 T u p l e , 则 T u p l e 2 ( 数据1,
数
据
2
)
3
)
数据2) 3)
数 据 2 ) 3 ) 数据1 -> $数据2 得到里面的数据:KaTeX parse error: Expected group after '_' at position 9: Tuple对象._̲ 索引(从1开始) Tuple 迭代
通过每个元素的索引得到数据 通过把 Tuple 转换成迭代器
package com. xk. bigdata. scala. collection
object TupleApp {
def main( args: Array[ String ] ) : Unit = {
val tuple1 = ( 1 , 2 , "spark" , "hadoop" )
val tuple2 = Tuple2( 1 , "spark" )
println( tuple1. _1)
val tuple3 = 0 - > "zero"
println( tuple3)
for ( i <- 0 until ( tuple3. productArity) ) {
println( tuple3. productElement( i) )
}
for ( els <- tuple3. productIterator) {
println( els)
}
}
}
4. Map
Map是一种可迭代的键值对(key/value)结构。 所有的值都可以通过键来获取。 Map 中的键都是唯一的。 我们经常使用:HashMap、SortedMap
4.1 不变集合-Map
定义:Map($key -> $value) 得到Map里面数据:
M
a
p
对
象
.
g
e
t
O
r
E
l
s
e
(
Map对象.getOrElse(
M a p 对 象 . g e t O r E l s e ( Key, $默认值(如果没有这个Key,则返回默认值)) 得到Map里面的所有的Key:$Map对象.keys 得到Map里面的所有的Value:$Map对象.values 遍历Map:
4.2 可变集合-Map
定义:scala.collection.mutable.Map [$Key数据类型, $Value数据类型] () 插入数据:
M
a
p
对
象
.
p
u
t
(
Map对象.put(
M a p 对 象 . p u t ( Key,$Value)$Map对象 += $Key -> $Value
M
a
p
对
象
+
+
=
M
a
p
(
Map对象 ++= Map(
M a p 对 象 + + = M a p ( Key -> $Value)
package com. xk. bigdata. scala. collection
object MapApp {
def main( args: Array[ String ] ) : Unit = {
val map1 = Map( "hadoop" - > 21 , "spark" - > 22 )
println( map1. getOrElse( "hadoop" , 0 ) )
println( map1. getOrElse( "hadoop1" , 0 ) )
map1. keys. foreach( println)
map1. values. foreach( println)
for ( key <- map1. keys) {
println( s"key==============>$key" )
val value = map1. getOrElse( key, 0 )
println( s"value=============>$value" )
}
for ( key <- map1. keySet) {
println( s"key==============>$key" )
val value = map1. getOrElse( key, 0 )
println( s"value=============>$value" )
}
val map2 = scala. collection. mutable. Map[ String , Int ] ( )
map2. put( "hbase" , 20 )
map2 += "flink" - > 21
map2 ++ = Map( "kafka" - > 25 )
println( map2)
}
}
5. Queue(队列)
队列实现了一种数据结构, 该结构允许以先进先出(FIFO)的方式插入和检索元素。 添加元素:
队
列
对
象
.
e
n
q
u
e
u
e
(
队列对象.enqueue(
队 列 对 象 . e n q u e u e ( 队列数据…) 取出数据:$队列对象.dequeue(),取出队列中的第一条数据,先进先出 取出第一条数据:$队列对象.head,第一条数据不会被取出 取出除第一条以外的数据:$队列对象.tail 队列同样分成可变队列以及不可变队列
5.1 不可变队列
定义:scala.collection.immutable.Queue [
数
据
类
型
]
(
数据类型] (
数 据 类 型 ] ( 队列数据)
5.2 可变队列
定义:new mutable.Queue [$数据类型] ()
package com. xk. bigdata. scala. collection
import scala. collection. mutable
object QueueApp {
def main( args: Array[ String ] ) : Unit = {
val queue1 = scala. collection. immutable. Queue[ Int ] ( 2 , 3 , 4 , 5 , 5 )
println( queue1)
val queue2 = new mutable. Queue[ Int ] ( )
queue2. enqueue( 2 , 3 , 4 , 5 , 6 )
println( queue2)
queue2. dequeue( )
println( queue2)
queue2. head
println( queue2)
println( queue2. tail)
}
}
6. List
Scala 列表类似于数组,它们所有元素的类型都相同,但是它们也有所不同:列表是不可变的,值一旦被定义了就不能改变,其次列表 具有递归的结构(也就是链接表结构)而数组不是。 Nil 为一个空列表 head 返回列表第一个元素 tail 返回一个列表,包含除了第一元素之外的其他元素 isEmpty 在列表为空时返回true 除最后一个元素以外的其他元素:init List.reverse 用于将列表的顺序反转 删除列表数据:drop 遍历
直接使用加强的 For 循环 把 List 转换成可迭代,然后进行迭代
6.1 不可变列表
6.2 可变列表-ListBuffer
定义:scala.collection.mutable.ListBuffer [$数据类型] 添加数据:
$List对象 += $单个列表数据 $List对象 ++= $列表数据
package com. xk. bigdata. scala. collection
object ListApp {
def main( args: Array[ String ] ) : Unit = {
val list1 = List( "spark" , "hadoop" , "flink" , "kafka" )
println( list1. head)
println( list1. tail)
println( list1. isEmpty)
println( list1. init)
println( list1. reverse)
println( list1. drop( 1 ) )
for ( els <- list1) {
println( els)
}
val iterator = list1. iterator
while ( iterator. hasNext) {
println( iterator. next( ) )
}
val listBuffer = scala. collection. mutable. ListBuffer[ String ] ( )
listBuffer += "hadoop"
listBuffer ++ = List( "spark" , "flink" )
println( listBuffer)
}
}
7. 练习
使用之前学习的知识,使用递归方法实现一个累加功能。 使用递归方法的时候,递归方法必须手动定义返回值类型。
package com. xk. bigdata. scala. collection
object RecursAddApp {
def main( args: Array[ String ] ) : Unit = {
println( sum( 1 , 2 , 3 , 4 , 5 ) )
}
def sum( nums: Int * ) : Int = {
if ( nums. length == 0 ) {
0
} else {
nums. head + sum( nums. tail: _* )
}
}
}
8. 函数式编程
8.1 函数和方法
函数和方法的区别:
方法不能作为单独的表达式而存在(参数为空的方法除外),而函数可以。 函数必须要有参数列表,而方法可以没有参数列表。 方法名是方法调用,而函数名只是代表函数对象本身。 在需要函数的地方,如果传递一个方法,会自动进行ETA展开(把方法转换为函数)。 传名参数本质上是个方法。 函数的定义:
val/var 函数名称 = (输入参数列表) => {函数体} val/var 函数名称:(输入参数类型) => 返回值类型 = (输入参数的引用) => {函数体} 高阶函数:参数为函数的函数。 常用的高阶函数:
柯里化函数:指的是将原来接受两个参数的函数变成新的接受一个参数的函数的过程。新的函数返回一个以原有第二个参数为参数的函数。
package com. xk. bigdata. scala. function
object FunctionBasic {
def main( args: Array[ String ] ) : Unit = {
val f1 = ( a: Int , b: Int ) => a + b
println( f1( 1 , 2 ) )
def add( a: Int , b: Int ) : Int = a + b
val addFun = add _
println( addFun( 2 , 4 ) )
val f2: ( Int , Int ) => Int = add
println( f2( 4 , 5 ) )
def f3( op: ( ( Int , Int ) => Int ) ) = {
op( 2 , 3 )
}
println( f3( ( a, b) => {
a + b
} ) )
def f4( a: Int , b: Int ) ( op: ( ( Int , Int ) => Int ) ) = {
op( a, b)
}
println( f4( 4 , 20 ) ( ( a, b) => {
a + b
} ) )
}
}
8.2 自定义实现Map
map 的作用会把集合里面的所有元素,全部做同样的操作,返回一个集合。
package com. xk. bigdata. scala. function
object CustomMapFun {
def customMap( array: Array[ Int ] ) ( op: ( Int ) => Int ) : Array[ Int ] = {
for ( els <- array) yield op( els)
}
def main( args: Array[ String ] ) : Unit = {
val array = Array( 1 , 2 , 3 , 4 , 5 )
array. map( _ * 2 ) . foreach( println)
customMap( array) ( _ * 2 ) . foreach( println)
}
}
8.3 自定义实现reduce
reduce 是把集合中两两相近的元素进行同一个操作,最终计算出一个结果。
package com. xk. bigdata. scala. function
object CustomReduceFun {
def customReduce( array: Array[ Int ] ) ( op: ( Int , Int ) => Int ) : Int = {
var last = array( 0 )
for ( i <- 1 until ( array. length) ) {
last = op( last, array( i) )
}
last
}
def main( args: Array[ String ] ) : Unit = {
val array = Array( 1 , 2 , 3 , 4 , 5 )
println( array. reduce( ( a, b) => {
println( s"a:${a}=====>b:$b" )
a + b
} ) )
println( customReduce( array) ( ( a, b) => {
println( s"a:${a}=====>b:$b" )
a + b
} ) )
}
}
8.4 自定义实现filter
package com. xk. bigdata. scala. function
object CustomFilterFun {
def customFilter( array: Array[ Int ] ) ( op: ( Int ) => Boolean ) : Array[ Int ] = {
for ( els <- array if op( els) ) yield els
}
def main( args: Array[ String ] ) : Unit = {
val array = Array( 1 , 2 , 3 , 4 , 5 )
array. filter( _ > 3 ) . foreach( println)
customFilter( array) ( _ > 3 ) . foreach( println)
}
}
8.5 自定义实现foreach
foreach 是对集合中每个元素做同一个操作,返回值为 Unit
package com. xk. bigdata. scala. function
object CustomForeachFun {
def customForeach( array: Array[ Int ] ) ( op: ( Int ) => Unit ) : Unit = {
for ( els <- array) op( els)
}
def main( args: Array[ String ] ) : Unit = {
val array = Array( 1 , 2 , 3 , 4 , 5 )
array. foreach( println)
customForeach( array) ( println)
}
}
8.6 其他常用算子的使用
flatten:压平 flatMap:压平+ Map,可以理解等于 flatten 算子 + map 算子 groupBy:按照某个字段分组 mapValues:对Map里所有的value施加一个map函数,返回一个新的Map sortBy:按照某个字段排序 take:得到前几条数据
package com. xk. bigdata. scala. function
object OtherFun {
def main( args: Array[ String ] ) : Unit = {
val array = Array( "spark,hbase" , "spark,hadoop" , "spark,hadoop" , "kafka" )
array. flatten. foreach( println)
array. map( _. split( "," ) ) . flatten. foreach( println)
val words = array. flatMap( _. split( "," ) )
val groupBy = words. map( ( _, 1 ) ) . groupBy( _. _1)
groupBy. mapValues( _. size) . toArray. sortBy( - _. _2) . take( 2 ) . foreach( println)
}
}
9. 使用 Scala 实现 WC
hadoop,spark,hadoop,flink
spark,hbase,kafka
hadoop
package com. xk. bigdata. scala. wc
import scala. io. Source
object WcApp {
def main( args: Array[ String ] ) : Unit = {
val list = Source. fromFile( "data/wc.txt" ) . getLines( ) . toList
list. flatMap( _. split( "," ) )
. map( ( _, 1 ) )
. groupBy( _. _1)
. mapValues( _. size)
. foreach( println)
}
}
10. 模式匹配
如果代码中有多个 if else if 的时候,Java 中可以使用 switch case 来解决,Scala 模式匹配对应了 Java 中的 switch case。 在模式匹配最后一个匹配项写 case _ 是指的不满足以上条件的,执行后面的代码。 在 Scala 中模式匹配最常用的场景就是在捕获异常的时候。
package com. xk. bigdata. scala. pattern
import scala. io. Source
object PatternApp {
def main( args: Array[ String ] ) : Unit = {
judgeGrade1( "A" )
judgeGrade1( "B" )
judgeGrade1( "E" )
judgeGrade2( "A" , "hadoop" )
judgeGrade2( "E" , "spark" )
judgeFriend1( Array( "spark" ) )
judgeFriend1( Array( "spark" , "hadoop" ) )
judgeFriend1( Array( "flink" , "hadoop" ) )
judgeFriend1( Array( "flink" , "hadoop" , "spark" ) )
judgeFriend2( List( "spark" ) )
judgeFriend2( List( "spark" , "hadoop" ) )
judgeFriend2( List( "flink" , "hadoop" ) )
judgeFriend2( List( "flink" , "hadoop" , "spark" ) )
judgeDataType( "data" )
judgeDataType( 1 )
judgeDataType( Map( "spark" - > 21 ) )
judgeDataType( List( "Spark" ) )
judgeDataType( 1L )
judgeClass( Person( "spark" ) )
judgeClass( Student( 21 ) )
judgeClass( 1 )
tryCatch( )
}
def judgeGrade1( grade: String ) : Unit = {
grade match {
case "A" => println( "很好!!" )
case "B" => println( "还不错!!" )
case "C" => println( "需要加油了!!" )
case _ => println( "其他分数!!" )
}
}
def judgeGrade2( grade: String , name: String ) : Unit = {
grade match {
case "A" => println( "很好!!" )
case "B" => println( "还不错!!" )
case _ if ( name == "spark" ) => println( s"$name 还可以!!" )
case _ => println( "其他的!!" )
}
}
def judgeFriend1( array: Array[ String ] ) : Unit = {
array match {
case Array( "spark" ) => println( "Hi spark" )
case Array( "spark" , _* ) => println( "Hi spark and friends" )
case Array( x, y) => println( s"Hi ,$x==>$y" )
case _ => println( "大家好" )
}
}
def judgeFriend2( list: List[ String ] ) : Unit = {
list match {
case "spark" : : Nil => println( "Hi spark" )
case "spark" : : tail => println( "Hi spark and friends" )
case List( x, y) => println( s"Hi ,$x==>$y" )
case _ => println( "大家好" )
}
}
def judgeDataType( data: Any ) : Unit = {
data match {
case i: Int => println( "Int" )
case s: String => println( "String" )
case map: Map[ _, _] => println( "map" )
case list: List[ _] => println( "list" )
case _ => println( "其他类型" )
}
}
def judgeClass( obj: Any ) : Unit = {
obj match {
case Person( name) => println( s"Person=======>$name" )
case Student( age) => println( s"Student=========>$age" )
case _ => println( "other..." )
}
}
case class Person( name: String )
case class Student( age: Int )
def tryCatch( ) : Unit = {
try {
1 / 0
Source. fromFile( "data/demo.txt" )
} catch {
case e: ArithmeticException => println( s"计算异常:${e.getMessage}" )
case e: Exception => println( s"${e.getMessage}" )
}
}
}
11. 偏函数
偏函数:被包在花括号里面的没有match的一组case语句 定义:PartialFunction[-A, +B]
package com. xk. bigdata. scala. pattern
object PartitalFunctionApp {
def main( args: Array[ String ] ) : Unit = {
println( judgeGrade( "A" ) )
println( judgeGrade( "B" ) )
println( judgeGrade( "E" ) )
val list = List( 1 , 2 , 3 , 4 , 5 , "hadoop" , "spark" )
val pair1 = new PartialFunction[ Any , Int ] {
override def isDefinedAt( x: Any ) : Boolean = {
x. isInstanceOf[ Int ]
}
override def apply( v1: Any ) : Int = {
v1. asInstanceOf[ Int ] * 10
}
}
list. collect( pair1) . foreach( println)
val pair2: PartialFunction[ Any , Int ] = {
case i: Int => i * 10
}
list. collect( pair2) . foreach( println)
list. collect( {
case i: Int => i * 10
} ) . foreach( println)
list. collect {
case i: Int => i * 10
} . foreach( println)
}
def judgeGrade: PartialFunction[ String , String ] = {
case "A" => "很好!!"
case "B" => "还不错!!"
case "C" => "需要加油了!!"
case _ => "其他分数!!"
}
}