1.数组反转
object ExcuDemo {
def swapArray(arr:Array[Int]) ={
//这里只能使用until
for (i <- 0 until arr.length-1 if(i%2==0)){
arr(i) = arr(i)^arr(i+1)
arr(i+1) = arr(i)^arr(i+1)
arr(i) = arr(i)^arr(i+1)
}
arr
}
def main(args: Array[String]): Unit = {
val arr = Array[Int](2,3,4,8,6,9,7,1,3)
swapArray(arr).toList.foreach(x=>print(x+" "))
//3 2 8 4 9 6 1 7 3
println()
//指定两个元素为一组
val res: Iterator[Array[Int]] = arr.grouped(2)
val res2: Iterator[Array[Int]] = res.map(x=>x.reverse)
val res3: Iterator[Int] = res2.flatten
while(res3.hasNext){
print(res3.next()+" ")
//3 2 8 4 9 6 1 7 3
}
}
}
2.Key和value互换
import scala.collection.mutable.ListBuffer
object Text6 {
def main(args: Array[String]): Unit = {
/**
* 6,key value互换
val lst = List("Id1-The Spark","Id2-The Hadoop","Id3-The Spark")
结果值:
The-Id1 Id2 Id3
Spark-Id1 Id3
Hadoop-Id2
*/
val lst = List("Id1-The Spark","Id2-The Hadoop","Id3-The Spark")
//切割,组合
val res: List[Array[(String,String)]] = lst.map({
t =>
val res1 = t.split("-")
val key: String = res1(0)
val values: Array[String] = res1(1).split(" ")
val res2: Array[(String, String)] = values.map(x=>(x,key))
res2
})
res.foreach(x=>print(x.toBuffer))
//ArrayBuffer((The,Id1), (Spark,Id1))ArrayBuffer((The,Id2), (Hadoop,Id2))ArrayBuffer((The,Id3), (Spark,Id3))
//压平
println()
val res2: List[(String, String)] = res.flatten
res2.foreach(print)
//(The,Id1)(Spark,Id1)(The,Id2)(Hadoop,Id2)(The,Id3)(Spark,Id3)
//聚合
println()
val res3: Map[String, List[(String, String)]] = res2.groupBy(x => x._1)
res3.foreach(print)
//(Hadoop,List((Hadoop,Id2)))(Spark,List((Spark,Id1), (Spark,Id3)))(The,List((The,Id1), (The,Id2), (The,Id3)))
//提取,组合
println()
val res4: Map[String, List[String]] = res3.mapValues({
t=>
t.map(x=>x._2)
})
res4.foreach(x=>print(x))
//(Hadoop,List(Id2))(Spark,List(Id1, Id3))(The,List(Id1, Id2, Id3))
println()
val res5 = res4.map({
t=>
t._1.concat("-").concat(t._2.mkString(" "))
//t._1.concat("-").concat(t._2.reduce(_+" "+_))
//(t._1,t._2.reduce(_+" "+_))
})
res5.foreach(x=>println(x))
}
}
3.交集,并集 差集——求平均温度
intersect union diff
object TempAvg {
def main(args: Array[String]): Unit = {
val d1 = Array(("bj",28.1), ("sh",28.7), ("gz",32.0), ("sz", 33.1))
val d2 = Array(("bj",27.3), ("sh",30.1), ("gz",33.3))
val d3 = Array(("bj",28.2), ("sh",29.1), ("gz",32.0), ("sz", 30.5))
val res1 = d1.union(d2).union(d3)
val res2 = d1.diff(d2).diff(d3)
val res3 = d1.intersect(d1).intersect(d3)
val res4 = d1 ++ d2 ++ d3
println(res1.toMap)
//Map(bj -> 28.2, sh -> 29.1, gz -> 32.0, sz -> 30.5)
val stringToTuples: Map[String, Array[(String, Double)]] = res1.groupBy(x=>x._1)
stringToTuples.foreach(x=>print(x._2.toBuffer))
//ArrayBuffer((gz,32.0), (gz,33.3), (gz,32.0))ArrayBuffer((bj,28.1), (bj,27.3),
// (bj,28.2))ArrayBuffer((sz,33.1), (sz,30.5))ArrayBuffer((sh,28.7), (sh,30.1), (sh,29.1))
//第一种方式:
println()
val result = stringToTuples.map({
x=>
val city:String = x._1
//获取相同城市的温度
val temp: Array[Double] = x._2.map(x=>x._2)
//求总温度
val tempSum: Double = temp.sum
val len = x._2.length
//求平均温度
val avg: Double = tempSum/len
//返回结果
(city,avg)
})
result.foreach(print)
//(gz,32.43333333333333)(bj,27.86666666666667)(sz,31.8)(sh,29.3)
//第二种方式:
println()
val values = stringToTuples.mapValues({
arr=>
//先求温度总和 用foldLeft
val sumTamp = arr.foldLeft(0.0)((x,y)=>x+y._2)
val length: Int = arr.length
sumTamp/length
})
values.foreach(print)
//(gz,32.43333333333333)(bj,27.86666666666667)(sz,31.8)(sh,29.3)
val arr = List(List(3),List(2,5),List(7,9))
//初始值必须有,运算中会被使用
//aggregate的底层调用的还是foldLeft
val d: Double = arr.aggregate(0.0)((x, y)=>x+y.sum,_+_)
print(d)//26.0
val arr1 = Array(1,2,3,4,5)
print(arr1.aggregate(10)(_+_,_+_))//25
}
}
4.面向对象
对象:object修饰
类:class修饰
类的实例:new class
1.对象
1)单例对象
Object修饰的对象不用static修饰,但是是静态的对象,称为单例对象
2)伴生对象
伴生对象是一种特殊的单例对象,需满足两个条件:
1.伴生对象和伴生类在同一个文件中
2.伴生对象名和伴生类名一样
这样的单例对象,被称作是这个类的伴生对象。类被称为是这个单例对象的伴生类。
结论:类和伴生对象之间可以相互访问私有的方法和属性
class Dog {
val id = 1
private var name = "xiaoqing"
def printName(): Unit ={
//在Dog类中可以访问伴生对象Dog的私有属性
println(Dog.CONSTANT + name )
}
}
/**
* 伴生对象
*/
object Dog {
//伴生对象中的私有属性
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String]) {
val p = new Dog
//访问私有的字段name
p.name = "123"
p.printName()
}
}
3)Apply方法
Scala中的apply调用方法有两种:
1.在对象中调用;
对象名+方法名
2. 在类中调用
New class
类名+方法名
Object apply 主要用来解决复杂对象的初始化问题
class ApplyOperation {
}
class ApplyTest {
def apply() = println("I spark so much!!!")
def haveATry: Unit = {
println("try again")
}
}
object ApplyTest {
def apply() = {
println("I am Scala")
}
}
object ApplyOperation {
def main(args: Array[String]) {
val array = Array(1, 2, 3, 4)
//这里ApplyTest.apply()中的()可以省略;但是ApplyTest()de ()
//不能省略,shenglve后调用的是对象而不是类
val test = new ApplyTest()
val a = ApplyTest.apply //这里就是object中 apply 的使用
val b = ApplyTest()
val c = ApplyTest
test.haveATry//try again// 这里就是 class 中 apply使用
//a()// 这里就是 class 中 apply使用
c.apply() //I am Scala//这里就是object中 apply 的使用
}
}
4)应用程序对象
object AppObjectDemo extends App{
//不用写main方法
println("I love you Scala")
}
App源码:内含main方法
trait App extends DelayedInit {
/** The time when the execution of this program started, in milliseconds since 1
* January 1970 UTC. */
@deprecatedOverriding("executionStart should not be overridden", "2.11.0")
val executionStart: Long = currentTime
/** The command line arguments passed to the application's `main` method.
*/
@deprecatedOverriding("args should not be overridden", "2.11.0")
protected def args: Array[String] = _args
private var _args: Array[String] = _
private val initCode = new ListBuffer[() => Unit]
/** The init hook. This saves all initialization code for execution within `main`.
* This method is normally never called directly from user code.
* Instead it is called as compiler-generated code for those classes and objects
* (but not traits) that inherit from the `DelayedInit` trait and that do not
* themselves define a `delayedInit` method.
* @param body the initialization code to be stored for later execution
*/
@deprecated("The delayedInit mechanism will disappear.", "2.11.0")
override def delayedInit(body: => Unit) {
initCode += (() => body)
}
/** The main method.
* This stores all arguments so that they can be retrieved with `args`
* and then executes all initialization code segments in the order in which
* they were passed to `delayedInit`.
* @param args the arguments passed to the main method
*/
@deprecatedOverriding("main should not be overridden", "2.11.0")
def main(args: Array[String]) = {
this._args = args
for (proc <- initCode) proc()
if (util.Properties.propIsSet("scala.time")) {
val total = currentTime - executionStart
Console.println("[total " + total + "ms]")
}
}
}
2.类
类和对象,应该怎么使用???
优先使用对象,如果需要构造器,那么只能使用类。
如果需要封装数据的时候,需要使用到类。
1) 类定义
在Scala中,类并不用声明为public。
Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
var 修饰的变量, 这个变量对外提供getter setter方法
val 修饰的变量,是只读属性 对外提供了getter方法,没有setter(相当于java中用final修饰的变量)
class Student {
val id = 666
// _ 表示一个占位符, 编译器会根据变量的具体类型赋予相应初始值
// 注意: 使用_ 占位符是, 变量类型必须指定
var name: String = _
//用var修饰的变量既有getter又有setter
var age: Int = 20
}
object Test{
val name: String = "zhangsan"
def main(args: Array[String]): Unit = {
// 调用空参构造器,
val student = new Student()
student.name = "laowang"
// 类中使用val修饰的变量不能更改
// student.age = 20
println(s"student.name ====== ${student.name} ${student.age}")
println("Test.name ======" + Test.name)
}
}
2)构造器
scala的构造器
主构造器和辅助构造器
创建对象的同时对属性赋值,初始化赋值
主构造器,和类的定义交织在一起,如果主构造器的变量使用了val或var修饰,变成了类的一个成员属性,如果有var或val修饰则成员属性可以在类和对象中被调用,反之只能在本class中调用
辅助构造器,def this(参数列表),
辅助构造器的第一行,必须调用其他的构造器(主,辅助。。。)
辅助构造器和主构造器的参数列表,不能完全一致,参数类型和个数一致。
如果想定义空参的辅助构造器,调用的主构造器的参数必须赋值(初始化)
作用域范围:
主: 类中除了属性和方法之外,都是构造器的作用域
辅助: 只在自己的方法范围之内
/**
*每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
*/
class Person(val name: String, val age: Int){
//主构造器会执行类定义中的所有语句
println("执行主构造器")
private var gender = "male"
//用this关键字定义辅助构造器
def this(name: String, age: Int, gender: String){
//每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
this(name, age)
println("执行辅助构造器")
this.gender = gender
}
var account1:String=_
def this(name:String,age:Int,gender:String,account:String){
this(name,age,gender)
this.account1=account
}
println("这里还是主构造器")
}
object Person {
def main(args: Array[String]): Unit = {
val s = new Person ("laoduan", 38)
println(s"${s.name} ${s.age}")
val s1 = new Person (“dingding", 18, "female")
println(s"${s1.gender}")
val p2 =new Person("xx2",12,"female","9527")
println(s"${p2.age},${p2.account1}")
}
}
3)访问权限
对于成员属性,成员方法,构造器(主构造器,赋值xxx):
默认的: public
private: 类和其伴生对象中有效,其他地方无效
private [this] : 只在类中有效
private [package] : 指定包及其子包内有效
对于主构造器,private写在构造器的前面
对于类:
默认的:public
private private[this]:在当前包及其子包范围内有效
private [package]: 在指定包及其子包范围内有效
[edu360.scala.day02] : package写法是错误的
[day02]:正确的,只需要一个包名就ok了。
面向对象的特性:封装 继承 多态
4)抽象类
对象本质上拥有类的所有特性,但是object没有构造器,必须是无参的。
在Scala中, 使用abstract修饰的类称为抽象类. 在抽象类中可以定义属性、未实现的方法(抽象方法)和具体实现的方法。
//抽象类
abstract class Animal1{
//抽象字段
var name:String
var size:Int
//抽象方法
def walk
}
//抽象类实现类
class Cat(var length:Int)extends Animal1{
override var name = "cat"
override var size = 100
override def walk{
println(this.name + ":" + this.size + ":" + this.length)
}
}
object AbstractClassTest {
def main(args: Array[String]): Unit = {
val cat = new Cat(200)
println("name:" + cat.name)
println("size:" + cat.size)
println("length:" + cat.length)
cat.walk
}
}
3.特质
scala中没有interface implements
Trait(特质)相当于 java的接口。比接口功能更强大。特质中可以定义属性和方法的实现。
Scala的类只能够继承单一父类,但是可以实现(继承,混入)多个特质(Trait)使用的关键字是 with和extends
特质不能有任何的类参数,即传递给类的主构造器的参数。
比较:scala的trait和java中的interface的异同?
1,java的interface只定义方法名称和参数列表,不能定义方法体。而trait则可以定义方法体。
2,在java中实现接口用implements,而在scala中,实现trait用extends和with。
3,java的interface和scala的trait的最大区别是,scala可以在一个class实例化的时候动态混入trait。
用特质还是用抽象类??
1,优先使用特质。一个类可以扩展多个特质,但却只能扩展一个抽象类。
2,如果需要构造方法,使用抽象类。因为抽象类可以定义带参数的构造器,而特质不行。
trait T1 {
// 定义普通方法,有方法实现
def youcanfly()={
println("tai feng lai le you can fly")
}
}
trait T2 {
// 定义一个属性
val className: String = "NB大神班"
// 定义一个没有实现的方法,默认就是抽象方法
def teacherSay(name: String)
// 定义带有具体的实现的方法
def doSomething() = {
println("群主开始发红包了...")
}
def teach(subject:String)
}
class Teacher{
}
object test{
def main(args: Array[String]): Unit = {
// 动态混入特征,让类有了特质的方法
val t1 = new Teacher() with T1
println(t1.youcanfly())
// 动态混入特质不能使用extends关键字,可同时混入多个特质
val t = new Teacher() with T1 with T2{
// 如果特质中有抽象方法,则必须重写该抽象方法,可以不使用override关键字
def teacherSay(name:String)={
println(s"最高face,${name}")
}
// 重写一个有具体的实现的方法,必须使用关键字override
override def doSomething() = {
println("群主:抢到红包继续接龙...")
}
def teach(subject:String)={
println(s"${subject}:抢到红包继续接龙...")
}
}
println(t.teach("laozhao"))//laozhao:抢到红包继续接龙...
println(t.doSomething)//群主:抢到红包继续接龙...
println(t.youcanfly())//tai feng lai le you can fly
}
}
4.继承
在继承抽象类或者特质的时候,继承抽象类使用extends,实现特质用with和extends,当类只实现了特质的时候,第一个关键字必须是extends
实现类还是特质,抽象方法都必须被实现,而且可以不使用override关键字
重写非抽象方法,必须使用override关键字
特质支持动态混入,在类实例化的时候,可以通过with关键字混入特质。
特质不能有构造器,抽象类可以有。
// 定义一个抽象类
abstract class Animal(val age: Int) {
println("Animal`s main constructor invoked" + age)
//定义一个抽象方法
def run()
def breath(): Unit = {
println("呼吸氧气")
}
}
// 定义一个特质,定义一个普通方法
trait Fightable {
def fight(): Unit = {
println("用嘴咬")
}
}
// 定义一个特质,一个抽象方法
trait Flyable {
// 定义一个抽象方法
def fly()
}
//在scala中,不论是继承还是实现特质,第一个都用extends关键字
class Bird extends Flyable with Fightable {
override def fly(): Unit = {
println("用翅膀飞")
}
}
object Bird {
def main(args: Array[String]): Unit = {
val b = new Bird
b.fly()
}
}
class Monkey(age: Int) extends Animal(age) with Flyable with Fightable {
//重写抽象的方法, 可以不加override关键字
def run(): Unit = {
// super()
println("跳着跑")
}
//重写非抽象的方法,必须加override关键字
override def breath(): Unit = {
println("猴子呼吸")
}
override def fly(): Unit = {
println("乘着筋斗云飞")
}
override def fight(): Unit = {
println("用棒子打")
}
println("monkey`s main constructor invoked" + age)
}
object Monkey {
def main(args: Array[String]): Unit = {
val a: Animal = new Monkey(100)
a.breath()
}
}
5.模式匹配
1.样例类/样例对象
样例类:使用case关键字 修饰的类,重要的特征就是支持模式匹配,多例
样例object:使用case关键字修饰的对象,支持模式匹配,单例
case class 和 class的一些区别:
case class在初始化的时候,不用new,而普通类初始化时必须要new。
case class 重写了toString方法。默认实现了equals和hashCode实现了序列化接口
在Scala中样例类是一中特殊的类,可用于模式匹配。case class是多例的,case class 支持模式匹配(最重要的特征),所有case class 必须要有参数列表,有参数用case class,无参用case object
import scala.util.Random
case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask
object CaseDemo04 extends App{
val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
arr(Random.nextInt(arr.length)) match {
case SubmitTask(id, name) => {
println(s"$id, $name")
}
case HeartBeat(time) => {
println(time)
}
case CheckTimeOutTask => {
println("check")
}
}
}