从零学scala(七)集合、模式匹配和样例类

一:集合

主要的集合特质

scala集合中重要的特质:

Trait(Iterable)
Trait(Seq) Trait(Set) Trait(Map)
Trait(IndexedSeq) Trait(SoredSet) Trait(SoredMap)

Seq是一个有先后次序的值的序列,比如数组和列表。IndexSeq允许我们通过下表快速访问元素,ArrayBuffer是带下标的,但是链表不是。

Set是一个没有先后次序的值的序列,SortedSet中,元素以排过序的顺序被访问。

Map是一组(键,值)对偶。SortedMap是按照插入顺序访问实体。

//插入一点新的:每一个集合或者类都有apply的伴生对象,他可以用来构建集合中的实例。这个原则叫做:“”统一创建原则“”

可变和不可变集合

scala中有两种集合:可变的和不可变的。scala优先使用不可变的。

val map = Map("a"->1,"b"->"2","c"->3)
         println(map.apply("a"))

序列

不可变序列

Sep<trait>
IndexSep<trait> List Stream Stack Queue
Vector Range

Vector是ArrayBuffer的不可变的版本:一个带下标的序列,支持快速的随机访问。向量是以树形结构的形式实现的,每个节点不超过32个子节点。对于100万个元素,只需要4层就能完成。

Range表示一个整数序列。

可变序列  

Sep<trait>
IndexSep<trait> Stack Queue Priority Queue LinkedList Double LinkedList
ArrayBuffer

列表

val list = List(4,2,3)
         println(list.head)   //第一个元素
         println(list.tail)      //将除了第一个元素的所有元素作为一个List
         println(list.sum)    //集合求和

可变列表

LinkedList  //现在的版本已经弃用

set是不重复元素的集合,并且元素不以插入顺序存储
          val set = scala.collection.mutable.Set("1","2","3")
          set.+=("3")
          println(set.mkString("|"))

//如果要用插入顺序被记住的set,那就使用LinkedHashSet
          val set = scala.collection.mutable.LinkedHashSet("1","2","3")
          set.+=("4")
          println(set.mkString("|"))

//如果要是用插入自动排序的集合,那就使用SortedSet
          val set = scala.collection.mutable.SortedSet("4","7","1")
          set.+=("5")
          println(set.mkString("|"))

基本上和JAVA一致的

用于添加或去除元素的操作符

操作符 描述 集合类型
:+、+:  将元素插入到集合的头部或者尾部 Seq
+(ele*) 添加了给定元素的与集合相同的集合 Set、Map
-(ele*) 删除了给定元素的与集合相同的集合 Set、Map、ArrayBuffer
++ 与coll元素类型相同的集合相加 Iterable
-- 与coll元素类型相同的集合相减 Set、Map、ArrayBuffer

|

&


|等于相加

&等于--

Set

+=

++=

-=

--=

删除和添加元素 可变集合

+=

++=

向前追加元素来修改coll ArrayBuffer

都是一些基本的方法,大家在使用过程用用就知道,就不一一的举例了。 记住一点不可变的集合+-元素后生成新的集合。

  +:向前追加元素,:+向后追加元素,+是无序的。-删除元素,--删除集合,++添加元素。

常用方法

Iterable常用方法
方法 描述
head,last,headOption,lastOption 返回第一个元素或者返回最后一个元素。或者以Option集合的方式返回
tail,init tail:除了第一个元素之外的元素。int返回除了最后一个元素之外的元素。
map,foreach,flatMap,collect map对每个元素进行操作,foreach map相同的效果,flatMap一行变多行,collect变成数组
reduceLeft,reduceRight,foldLeft,foldRight 将运算符从左到右对每个元素遍历,例如:reduceLeft(+)就是将所有元素相加起来
sum,max,min,avg 集合求和,集合最大值,集合最小值,集合平均值,
count,forall,exists
count将表达式内容对每个元素遍历,求出个数。forall所有元素都满足返回true。

exists有元素满足就返回true

filter,filterNot,partition
filter对每个元素循环进行条件过滤,filternot;filter的反面,

partition:对每个分区进行一个操作,一个partition可能包含多个元素。

平时的map是一个元素一个元素的遍历,但是partition相当于一次拿一堆的元素遍历,完了再拿一堆

takewhile,dropwhile,span
takeWhile,和dropWhile都比较好理解。

span相当于切分,返回两个集合,第一个满足条件,第二个不满足条件。

take,drop,splitAt splitAt按照第N的数组下标切分集合
takeRight,dropRight 从右往左拿N个元素和去掉N个元素
slice(i,j) 返回集合i,j中间的元素
zip,zipAll,zipWithIndex
zip返回压缩后的集合,set1.zipAll(set2, "20", "10")第一个集合填充10,第二个填充20,

zipWithIndex返回带下标的

grouped、sliding grouped  N个元素切割成一个集合,sliding(2):(12)(23)(34)(45)
mkString,addString, mkString生成字符串的方法,addString类似的方法,不过需要传递进去一个StringBuilder

toIterator,toSeq,toIndexedSeq,toArray,toList,

toStream,toSet,toMap

生成集合的方法
copyToArray,copyToBuffer copyToArray拷贝成数组,拷贝成Buffer
Seq的方法
contains,containsSlice,startsWith,endsWith 包含元素,包含序列,以序列开始,以序列结束
indexOf,lastIndexOf,indexOfSlice,lastIndexOfSlice 所在元素的下标,最后一个所在元素的下标,集合所在下标,最后一个集合所在下标
indexWhere 可以填写表达式
prefixLength,segmentLength 以条件表达式开头的序列的集合长度两个方法都是
padTo 转换成N的数组,不足的第二个参数填充
intersect 交集,diff:调用者和参数集合的差别
reverse 反转
sort、sortBy、sortWith 排序
combinations,permutations 随机抽取N个元素,对所有的元素进行不同排序返回

上述所有的方法不改变本身结合,只是在原有集合上操作返回一个新的集合

将函数映射到集合

这章的意思是对于遍历集合可以使用map函数,或者flatMap函数

seq1.map { x => println(x) }

val seq1 = Seq("1",Seq("2","3"))
          seq1.flatMap(x =>{
                    x.toString().split(",")
          }).map { x => println(x) }

seq1.foreach { x => println(x.toString()) }

化简、折叠和扫描

val seq1 = List(1,2,3,4)
          println(seq1.reduceLeft(_ + _)) // ((1+2)+3)+4
          println(seq1.reduceRight(_ + _)) // 1+(2+(3+4))
          
          println(seq1.foldLeft(10)(_ + _)) // ((10 + 1+2)+3)+4
          println(seq1.foldRight(10)(_ + _)) // 1+(2+(10 + 3+4))
          
          println(seq1.scanLeft(10)(_ + _)) // 打印所有的中间结果
          println(seq1.scanRight(10)(_ + _)) // 打印所有的中间结果

拉链操作

val seq1 = List(1,2,3,4)
          val seq2 = List("a","b","c","d")
          println(seq1.zip(seq2).mkString("|"))//压缩
          println(seq1.zipAll(seq2,5,"e").mkString("|"))//前一个seq填充5,后一个seq填充e
          println(seq1.zipWithIndex.mkString("|"))//带数组下表的压缩

迭代器

val seq2 = List("a","b","c","d").toIterator
          while(seq2.hasNext){
                    println(seq2.next())
          }

//scala中有很多可以循环列表的操作,个人不太喜欢用iter,比较喜欢用map。可能是spark写多了的原因

iter每次调用next都会改变iter的指向,这时候你就需要流了。流是尾部被懒计算的不可变的列表,也就是说当你需要时候他才会被计算,不过他会缓存你访问过的数据,方便你下次访问。

val seq1 = Source.fromFile("D:\\log_network.txt").getLines().toStream
          println(seq1.toString())//返回的内容是(****,?)只有你要的时候它才会去计算
          println(seq1.take(4).force.mkString("\r\n"))//强制取回来4个元素
          //若果你想取出来所有的值,书中的建议是使用iter进行循环。哈哈哈,作者的这个例子举错了

懒试图

val seq1 = Seq(1,2,3,4,5,6,7,8,9).view.map { x => x.toInt*100 }
          println(seq1.mkString("|"))
          //你可以对任何的集合使用view方法,以达到流的效果(需要的时候采取计算)
          //但是他不会进行任何缓存,你获取一次,它计算一次。
          //流连第一个元素都不会求值。force方法可以使它强制求值。

与Java集合的互操作

scala集合到Java集合

函数 scala类型 java类型
asJavaCollection Iterable Collection
asJavaIterable Iterable Iterable
asJavaIterator Iterator Iterator
asJavaEnumeration Iterator Enumeration
seqAsJavaList Seq List
mutableSeqAsJavaList muable.Seq List
bufferAsJavaList muable.buffer List
setAsJavaSet Set Set
mutableSetAsJavaSet muable.Set Set
mapAsJavaMap Map Map
mutableMapAsJavaMap muable.Map Map
asJavaDictionary Map Dictionary

java集合到scala集合的转换

函数 java类型 scala类型
collectionAsScalaIterable Collection Iterable
iterableAsScalaIterable Iterable Iterable
asScalaIterator Iterator Iterator
enumerationAsScalaIterator Enumeration Iterator
asScalaBuffer List muable.buffer
asScalaSet Set muable.Set
mapAsScalaMap Map muable.Map
dictionaryAsScalaMap Dictionary muable.Map
propertiesAsScalaMap Properties muable.Map

线程安全的集合

文章中提到的集合都过期了,在此就不进行举例了。

并行集合

val a = (1 to 100000)     //集合都有一个par方法,是可以利用到系统的多处理器的,我的机器上暂时没有显示出来乱序,大家可以试试
          val data = for(i <- a.par) yield i
          println(data.mkString("\r\n"))

二:模式匹配和样例类

更好的switch

val data = 15
          val change = data match {
                    case 10 => 10
                    case 100 => 100
                    case 1000 => 1000
                    case _ => 100000000
          }
          //scala不需要显示的写break,_会catch住别的情况

守卫

模式中的变量

val data = "150s"
          var mm = 150
          var change = 1234
          data match {
                    case "10s" => 10
                    case "100s" => 100
                    case "1000s" => 1000
                    case "mm" => change == -100
                    case "Math.PI" => change == -100
                    //如果case和关键字一致,可以使用""引起来
          }
          println(mm)
          println(change) //书上说:如果case后面跟着一个变量名。
          //那么表达式会被赋值给那个变量。如上代码实验,但是没有得到结果。
          //我猜测他想表达的意思应该是case后面可以跟变量

类型模式

var data:Any = ""
          var change = data match {//可以对任何类型进行匹配
                    case int:Int => 10
                    case string:String => "10"
                    case float:Float => "10.0f"
                    case double:Double => "10.0d"
          }
          println(change)

匹配数组、列表和元组

var data:Any = Array(0)//数组的匹配
          var change = data match {//可以对任何类型进行匹配
                    case Array(0) => "数组只有一个元素是0"
                    case Array(x,y) => "数组有两个元素" + x + "|" + y
                    case Array(0,_*) => "数组第一个元素是0"
                    case _ => "别的东西"
          }
          println(change)

var data:Any = List(0,1)//List的匹配
          var change = data match {//可以对任何类型进行匹配
                    case 0 :: Nil => "只有一个元素是0"
                    case x :: y :: Nil => "有两个元素" + x + "|" + y
                    case 0 :: tail => "第一个元素是0"
                    case _ => "别的东西"
          }
          println(change)

var data:Any = (0,1)//元组的匹配
          var change = data match {//可以对任何类型进行匹配
                    case (0,_) :: Nil => "有两个元素,第一个元素是0"
                    case (_,0) :: Nil => "有两个元素,第二个元素是0"
                    case _ => "别的东西"
          }
          println(change)

提取器

var data:Any = Array(0)//数组的匹配
          var change = data match {//可以对任何类型进行匹配
                    case Array(x,y) => "数组有两个元素" + x + "|" + y
          }
          println(change)
          //Array的伴生对象就是一个提取器,它定义了一个unapplySeq方法,该方法被
          //调用的时候,产生一个数组,第一个值赋给x,第二个值赋给y。
          //上面是提取器的一种使用方法,还有一种就是正则表达式

val pattern = "([0-9]+) ([a-z]+)".r
          "99 bottles" match{
                    case pattern(num,bottles) => println(num+"|"+bottles)
          }

变量声明中的模式

val x,y = (1,2) //将x赋值为1,将y赋值为2
          val Array(first,second,_*) = Array(1,2,3,4)//数组赋值给
          println(first) //first是单独的变量
          println(second) //second是单独的变量

for表达式中的模式

for((k,v) <- System.getProperties.toMap if k != "")
                    println(k + "|" + v)
          //对映射中的每一个(键、值)对偶,K被绑定到健,V被绑定到值。

样例类

abstract class Amount
          case class Dollar(value:Double) extends Amount
          case class Currency(value:Double,unit:String) extends Amount

val amt:Any = Dollar(1.0d)
          amt match{
                    case Dollar(value)=>println("Dollar class")
                    case Currency(value,unit)=>println("Currency class")
          }

//case class:唯一用过一次的是在sparksql中将实体类转换为DataFrame,因为他有一个toDF方法。

copy方法和带名参数

val amt = Currency(1.0d,"amt")
          val price = amt.copy(2.0d, "price")
          println(price.toString())
          println(amt.toString())//个人感觉没有什么作用,因为是两个对象

case语句中的中置表示法

匹配嵌套结构

abstract class Item
          case class Article(description:String,price:Double) extends Item
          case class Bundle(description:String,price:Double,items:Item*) extends Item

val data = Bundle("Bundle 1",1.0,Article("Articlea 1",11.11),
                    Bundle("Bundle 2",2.0,
                    Article("Articlea 2",22.22),
                    Article("Articlea 3",33.33)
          ))
          //case Bundle(_,_,[email protected](_,_),rest)=>
          //个人严重不建议这种写法,代码写出来就是让人看的,这种写法太难看懂了

样例类是邪恶的吗

//这章是对上面case 乱七八糟的解释
          //在合适的地方,样例类是十分方便的:
          //1.模式匹配通常比继承更容易把我们引向更加易读精简的代码
          //2.构造时候不需要new
          //3.你将会得到toString、equals、hashCode和copy方法
          //对于一个参数里面有变量的样例类,我们实现equals或者hashCode
          //的时候,应该考虑的是尽量使用不可变东西,计算hash值,比如ID

密封类

sealed abstract class Amount
          case class Article(price:Double) extends Amount
          case class Bundle(price:Double,unit:String) extends Amount
          //密封类的好处就是所有的子类都必须在同一个文件中

模拟枚举

sealed abstract class Color
          case class Red() extends Color
          case class Yellow() extends Color
          case class Green() extends Color

val cor:Any = Red
          cor match{
                    case Red => "stop"
                    case Yellow => "hurry up"
                    case Green => "go"
          }
          //个人感觉还不如直接枚举

Option类型

//Map类的get方法返回一个option。对于没有给定的键,返回None
          //如果有值则返回None。用getOrElse更好
          val map = Map(1->1,2->2,3->3)
          println(map.getOrElse(5, 0))

偏函数

//偏函数就是被包在花括号内的一组case语句
          val data = (1 to 4)
          data.toList.map {
                    case 1 => println(1);
                    case 2 => println(2);
                    case 3 => println(3);
                    case 4 => println(4);
          }

原文地址:https://www.cnblogs.com/wuxiaolong4/p/11876969.html

时间: 2024-08-09 18:03:59

从零学scala(七)集合、模式匹配和样例类的相关文章

好程序员大数据教程分享Scala系列之模式匹配和样例类

好程序员大数据教程分享Scala系列之模式匹配和样例类1.样例类在Scala中样例类是一中特殊的类,样例类是不可变的,可以通过值进行比较,可用于模式匹配.定义一个样例类:1.构造器中每一个参数都是val,除非显示地声明为var 2.伴生对象提供apply ,让你不使用new关键字就能构造出相应的对象case class Point(x: Int, y: Int)创建样例类对象:val point = Point(1, 2)val anotherPoint = Point(1, 2)val yet

快学Scala第14章----模式匹配和样例类

本章要点 match表达式是一个更好的switch,不会有意外掉入到下一个分支的问题. 如果没有模式能够匹配,会抛出MatchError.可以用case _ 模式来避免. 模式可以包含一个随意定义的条件,称作守卫. 你可以对表达式的类型进行匹配:优先选择模式匹配而不是isInstanceOf/asInstanceOf. 你可以匹配数组.元组和样例类的模式,然后将匹配到的不同部分绑定到变量. 在for表达式中,不能匹配的情况会被安静的跳过. 样例类继承层级中的公共超类应该是sealed的. 用Op

模式匹配和样例类

模式匹配是类似switch-case特性,但更加灵活:也类似if-else,但更加简约. 1 def fibonacci(i : Any) : Int = i match { 2 case 0 => 0 3 case 1 => 1 4 case n : Int if (n > 1) => fibonacci(n -1) + fibonacci(n - 2) 5 case _ => 0 6 } 7 8 println(fibonacci(3)) 9 println(fibona

Scala笔记整理(七):模式匹配和样例类

[TOC] 可以用到switch语句 1.Scala强大的模式匹配机制,可以应用在switch语句.类型检查以及"析构"等场合. def swithOps: Unit ={ var sign = 0 val ch: Char = '+' ch match { case '+' => sign = 1 case '-' => sign = -1 case _ => sign = 0 } println("sign===> " + sign) }

【转】Scala学习——模式匹配和样例类

原文链接 http://nerd-is.in/2013-09/scala-learning-pattern-matching-and-case-classes/ 原文发表于:http://nerd-is.in/2013-09/scala-learning-pattern-matching-and-case-classes/ Scala强大的模式匹配机制,可以应用在switch语句.类型检查以及“析构”等场合. 样例类对模式匹配进行了优化. 更好的switch 1 2 3 4 5 6 7 8 va

【Scala篇】--Scala中Trait、模式匹配、样例类、Actor模型

一.前述 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 模式匹配机制相当于java中的switch-case. 使用了case关键字的类定义就是样例类(case classes),样例类是种特殊的类. Actor相当于Java中的多线程. 二.具体阐述 trait特性 1.概念理解 Scala Trait(特征) 相当于 Java 的接口,实际上它比接口还功能强大. 与接口不同的是,它还可以定义属性和方法的实现. 一般情况下Scala的类可以继承多个Tra

快学Scala(14)--模式匹配和样例类

更好的switch def main(args: Array[String]): Unit = { var sign: Int = 0 val ch: Char = '+' val color = Color.BLACK sign = ch match { case '+' => 1 case '-' => -1 case _ => 0 } color match { case Color.RED => ; case Color.BLACK => ; case _ =>

scala模式匹配与样例类

样本类:添加了case的类便是样本类.这种修饰符可以让Scala编译器自动为这个类添加一些语法上的便捷设定.如下: 1.添加与类名一致的工厂方法.也就是说,可以写成Var("x")来构造Var对象.    2.样本类参数列表中的所有参数隐式获得了val前缀,因此它被当作字段维护. 3.编译器为这个类添加了方法toString,hashCode和equals等方法. 模式匹配: match对应Java里的switch,但是写在选择器表达式之后.即: 选择器 match {备选项}. 一个

好程序员大数据教程Scala系列之样例类_Option_偏函数

好程序员大数据教程Scala系列之样例类_Option_偏函数,在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None).Some包装了某个值,None表示没有值. object?OptionDemo {??def?main(args: Array[String]) {????val?map = Map("a"?-> 1, "b"?-> 2)????val?v = map.get("b&q