dataframe scala 修改值_亲爱的,走近Scala

计算机语言那么多,为什么大数据的Spark和Flink选择Scala?

理由如下:

1. 兼容性(极度重用java,学过java的很容易上手scala)

2. 简洁(实现同样功能,代码是java的一半)

3. 高层级(将java抽象封装得更好)

4. 集大成者(当然,用不好也可能变成四不像)


2ce36eee694f42e73093ff0cf980ddd0.png

代码乱花渐欲迷人眼,浅草才能没马蹄。咱们先有一个感性的认识

36bf746fe7d092728da0f0868719a96b.png

​​第一步:一些简单的小例子

Shell解释器:

d09a5cbc7005a26b0bcf0a0c1da02707.png

输入1+2:

be2dd267724dc860cca4710837066c9b.png

res0,表示结果0,一个冒号(:),跟着表达式的类型(Int),一个等号(=),结果(3)

继续

af9018780fe65f4fe31485d01667685f.png

Hello world 万岁

7214201bec2c115dae42786ce729c986.png

​定义一些变量

046cff15a24fa38c7d3302f9b4139119.png

定义一些函数

a1c6e6f10ebe108f2350b63a1b7f190f.png

编写几个脚本: Hello.scala

189cbaa3999703e93e7819b0c56d3041.png

运行:

a1179a9351e3180633b0d2c73f09bce9.png

结果:

01af8c1a73d42b58f5042e671de45bf9.png

修改脚本

d59d5d9094a6c8541cc18949c90362ab.png

运行: ​

180976b63f4f00b6efd1eff35825ffd0.png

7e330f575fbfbaa935ad5750976dbd3b.png

​讲讲while:

d9a59f0feca76ecd2eb8e119b6b7c367.png

​讲讲foreach和for:

ab23320eb4eaccec5a3e31c9f1d20651.png

讲讲数组和方法调用

ed59ef41b35a4258e9e625fa1a364b83.png

​本例中的to实际上是带一个Int参数的方法。代码0 to 2被转换成方法调用(0).to(2)。 请注意这个语法仅在你显示指定方法调用的接受者时才起作用。不可以写println 10,但是可以写成“Console println 10”。

7fb12e079b95f68d6e562ba065600aaa.png

​方法调用(续): 当你在一个或多个值或变量外使用括号时,Scala会把它转换成对名为apply的方法调用。于是greetStrings(i)转换成greetStrings.apply(i)。 当然前提是这个类型实际定义过apply方法。所以这不是一个特例,而是一个通则。 类似的例子:带有括号里参数和等号右边的对象的update方法的调用。

05d619d260e2759597ea7f42e3ea1cb5.png

​讲讲List:

ed1db7911bd0cf6c45f37cb58647bc65.png

​如果一个方法被用作操作符标注,如a * b,那么方法被左操作数调用,就像a.*(b)——除非方法名以冒号结尾。这种情况下,方法被右操作数调用。因此,1 :: twoThree里,::方法被twoThree调用,传入1,像这样:twoThree.::(1)。

dfb72966e140a29236e0ef7938ea13f1.png

​讲讲Tuple元组:

3d10db7d1b011d8b65978fbc944034c2.png

​第一个元素是以99为值的Int,第二个是"luftballons"为值的String。Scala推断元组类型为Tuple2[Int, String],并把它赋给变量pair。

897fe95169649a8a16d492154348a884.png

​讲讲Set和Map:

30cf39a7f570bf4ed40484e97534b8d4.png

a5fa8d2228189a4aa6b1d95ba789c0f9.png

​错误示范

111d67012bb17b0d1ac8fe2da3f09008.png

​正确示范

a751625f4dd9254856fdade008c62f83.png

​显式定义HashSet

bc0731de27f569aea650a88d221bf88f.png

​其他类型的可变、不可变Set,如HashSet等,请自由发挥!

错误示范

47696d70d37b33c3cc6caf5f2be84e3b.png

​正确示范(可变映射)

28be704e00a43b6f99e8d487c12f8e88.png

​讲讲Set和Map: 错误示范 正确示范(可变映射) ->方法可以调用Scala程序里的任何对象,并返回一个包含键和值的二元元组 所以可推断出,scala的map中的键值对是以元组的形式存放的 正确示范(可变映射)

b11f62f03a4cc0771fad8e33f04b5c29.png

​讲讲函数式风格:

类java编程(指令式编程)

2289737f79bfe3e0f93502dd0fc8d7f7.png

​加入函数式风格

24ca32dde488441b3a0901754fba96d5.png

​更函数式

4d7d89e6abb987c8cce52ed9b4fe9a11.png

​函数的副作用:如果某个函数不返回任何有用的值,就是说其结果类型为Unit,那么那个函数唯一能让世界有点儿变化的办法就是通过某种副作用。

从文件里读取信息:

引入Source:

8ee6d994e9c87c86c46ef86b74365f32.png

​调用自身:

ec2471cc4170b1b6c198066a2bdb6136.png

​过程解释:

1. 从包http://scala.io引用名为Source的类。

2. 检查是否命令行里定义了至少一个参数。

3. 若是,则第一个参数被解释为要打开和处理的文件名。

4. 表达式Source.fromFile(args(0)),尝试打开指定的文件并返回一个Source对象,在其上调用getLines。函数返回Iterator[String],在每个枚举里提供一行包括行结束符的信息。

5. for表达式枚举这些行并打印每行的长度,空格和这行记录。

6. 如果命令行里没有提供参数,最后的else子句将在标准错误流中打印一条信息。

从文件里读取信息:

8ee6d994e9c87c86c46ef86b74365f32.png

8ee6d994e9c87c86c46ef86b74365f32.png

​复习一下函数式风格:

Source.fromFile(args(0)).getLines.foreach(line => print(line.length + " " + line))


34974b362f59988b79288e0e31350da0.png

第二步:类、字段、方法(对比java)

类:

adabc0bd2cbb1df5a77a319801f1e017.png

​ 在Scala里把成员公开的方法是不显式地指定任何访问修饰符。换句话说,你在Java里要写上“public”的地方,在Scala里只要什么都不要写就成。Public是Scala的缺省访问级别。

dcc406f982e5068cb3f46e34d903aa56.png

​类续(引入方法):

6e720cc15cc07ea3ae1e33515e8d6460.png

当你去掉方法体前面的等号时,它的结果类型将注定是Unit。

2108e07341b1109c81404e815ad7ace2.png

​带有大括号但没有等号的,在本质上当作是显式定义结果类型为Unit的方法。

f41168a0a70b09690798600303b9d0c5.png

​用“=”返回一个非Unit的值

单例对象:

Scala比Java更面向对象的一个方面是Scala没有静态成员。替代品是,Scala有单例对象:singleton object。除了用object关键字替换了class关键字以外,单例对象的定义看上去就像是类定义。

61f0b842c1b770938044dc43e4f7bd8f.png

当你在应用程序中需要一个新的唯一账号时,调用Account.newUniqueNumber()即可。

单例对象的分类:

1.独立对象

不与伴生类共享名称的单例对象称为独立对象。它可以用在很多地方,例如作为相关功能方法的工具类,或者定义Scala应用的入口点。跟java的静态方法类似。

2. 伴生对象 当单例对象与某个类共享同一个名称时,它就被称为是这个类的伴生对象(companion object)。类和它的伴生对象必须定义在同一个源文件中。类被称为是这个单例对象的伴生类(companion class)。类和它的伴生对象可以互相访问其私有成员。

bf491c06bf1127e52c8a0db36f9c2b5c.png

​继承自抽象类的例子:

扩展类的一个有用的使用场景是给出可被共享的缺省对象。举例来说,考虑在程序中引入一个可撤销动作的类:

4d4b932189a8c390cae80078923b783e.png

​运行scala程序:

在Java中,一个类要能独立运行,那么必须具有静态的main方法。 Scala借鉴了这种模式。在Scala中,为了运行一个Scala程序,你必须定义一个Scala对象并为其定义一个main方法:

8b587754c60cd69411d76603bd26766a.png

​为了使代码更简洁,Scala还提供了另外一种运行Scala程序的方式,那就是直接继承scala.Application接口(Trait)。

8840645da2cdacadf80a203ca69a0fe0.png

​原理: 之所以这里无须定义main方法,那是因为在Application这个接口中定义了一个main方法,main方法在执行时会初始化RunAppWithoutMain这个对象,并执行它的主构造方法,而所 有直接写在对象中的代码都会被scala编译器收集到主构造方法中,于是就被运行了。 直接继承自Application导致的副作用:

1. 无法接受命令行参数。因为args参数不会被传入

2. 在Scala中,如果一个程序是多线程的,那么这个程序必须具有一个main方法。所以第二种写法只能适用于单线程的程序

3. Application这个接口在执行一个程序的代码之前,需要进行一些初始化。而某些JVM不会对这些初始化代码进行优化。

一些基本类型:

Scala的基本类型与Java的对应类型范围完全一样。这让Scala编译器能直接把Scala的值类型:value type实例,如Int或Double,在它产生的字节码里转译成Java原始类型。

717d699471b1eb0fcbca9ed430178786.png

富包装器:

基本类型可以通过隐式转换:implicit conversion,使用富包装器的方法。 每个基本类型,都有一个“富包装器”可以提供许多额外的方法。

d5f8fd82a1ed7f7ef805bc2d0608e214.png

案例类(Case Class):

case class User(name: String, role: String = "user", addTime: Instant = Instant.now())

特点1:不可变

802d22af6e6a6a80f6b80d6e51f94d85.png

当我们修改 u1.role 时,u2 就会受到影响,Java 的解决方式是要么基于 u1.role 深度克隆一个新对象出来,要么新创建一个 Role 对象赋值给 u2。

特点2:对象拷贝

20bfb38f47d3d5aad90716b72285eadf.png

​特点3:调试信息清晰

4eaa28b51bd0a024ca626950302da4fd.png

c89d458b7b83785d27db0c23b7a03e62.png

e7e30ea0086471d5a394836f07945b6b.png

2f5915fbc3ad9eb33e1781584d306023.png

最后一步:控制结构和特质

if:

cddc466b40da2eda507ef0fe60a62dd9.png

while:

78b2f52beeb40c202196aa43567f1885.png

for:

0f3f16783c37ff95a9282b4f25a21592.png

for-yield:

ac69d794cb3fbda04e621745280db4c1.png

​首先把包含了所有当前目录的文件的名为filesHere的Array[File],转换成一个仅包含.scala文件的数组。对于每一个对象,产生一个Iterator[String](fileLines方法的结果,定义展示在代码7.8中),提供方法next和hasNext让你枚举集合的每个元素。这个原始的枚举器又被转换为另一个Iterator[String]仅包含含有子字串"for"的修剪过的行。最终,对每一行产生整数长度。这个for表达式的结果就是一个包含了这些长度的Array[Int]数组。

请注意放置yield关键字的地方。对于for-yield表达式的语法是这样的: for {子句} yield {循环体}

try-catch:

6c847df8185004e3c715c7f7b09f3329.png

也有finally:

1e788ed36e81c4de74c2b7b21ff1077d.png

​ match(模式匹配):

7eb924a69d1df75c954fd0ffbb2b1432.png

特质trait:

特质:是Scala里代码复用的基础单元。特质封装了方法和字段的定义,并可以通过混入到类中重用它们。 不像类的继承那样,每个类都只能继承唯一的超类,类可以混入任意个特质。

5ed366a80ddea3f47fcce7f59e39914a.png

这个特质名为Philosophical。由于没有声明超类,因此和类一样,有个缺省的超类AnyRef。

一旦特质被定义了,就可以使用extends或with关键字,把它混入到类中。

既可以带抽象方法,也可以带具体方法

29f4321f859c8f9df351e915e1bf6d4c.png

​特质可以将对象原本没有的方法与字段加入对象中 如果特质和对象改写了同一超类的方法, 则排在右边的先被执行.

c74d7527b3379c11ebc202476ac4a760.png

​特质的构造顺序

1. 调用超类的构造器;

2. 特质构造器在超类构造器之后、类构造器之前执行;

3. 特质由左到右被构造;

4. 每个特质当中,父特质先被构造;

5. 如果多个特质共有一个父特质,父特质不会被重复构造

6. 所有特质被构造完毕,子类被构造。

特质trait——字段

具体字段

6652ef76bcdcf81bd6970d1f2a7ab757.png

​1. 混入Ability特质的类自动获得一个run字段.

2. 通常对于特质中每一个具体字段, 使用该特质的类都会获得一个字段与之对应.

3. 这些字段不是被继承的, 他们只是简单的加到了子类中.任何通过这种方式被混入的字段都会自动成为该类自己的字段, 这是个细微的区别, 却很重要 。

抽象字段

828efc18fb6142b0af7bd3553e270064.png

​特质中未被初始化的字段在具体的子类中必须被重写 。

最后:特质不能有构造器参数. 每个特质都有一个无参构造器. 值得一提的是, 缺少构造器参数是特质与类唯一不相同的技术差别. 除此之外, 特质可以具有类的所有特性, 比如具体的和抽象的字段, 以及超类.。


4ec9034985e36e0108bb28297a467ee5.png

隐式转换-mongodb库对接

利用隐式转换,我们可以在不改动三方库代码的情况下,将我们的数据类型与其进行无缝对接。例如我们通过实现一个隐式转换,将 Scala 的 JsObject 类型无缝地对接到了 MongoDB 的官方 Java 驱动的查询接口中,看起就像是 MongoDB 官方驱动真的提供了这个接口一样。 同时我们也可以将来自三方库的数据类型无缝集成到现有的接口中,也只需要实现一个隐式转换方法即可。

24f554c5ea13d704809c22681666c64d.png

​值比较

Java的比较:

0e457f0dcc2ec39d4531f3461eed3a7a.png

Scala值比较:

4f56cb50f519ba748a36dbd8179e74e9.png

​Scala引用比较:

4d0cf96b8e0ca176a47e45b42c71b3a3.png

​类型推断

错误代码:

123b42d424c4913efb23300f93310b04.png

Java正确代码:

82f610568156446d07b4fefd07f537df.png

​Scala正确代码:

6ca3b1141d8fc204f89e519cbf409b51.png

Actor Model

1. 概念理解

Actor Model是用来编写并行计算或分布式系统的高层次抽象(类似java中的Thread)让程序员不必为多线程模式下共享锁而烦恼,被用在Erlang 语言上, 高可用性99.9999999 % 一年只有31ms 宕机Actors将状态和行为封装在一个轻量的进程/线程中,但是不和其他Actors分享状态,每个Actors有自己的世界观,当需要和其他Actors交互时,通过发送事件和消息,发送是异步的,非堵塞的(fire-andforget),发送消息后不必等另外Actors回复,也不必暂停,每个Actors有自己的消息队列,进来的消息按先来后到排列,这就有很好的并发策略和可伸缩性,可以建立性能很好的事件驱动系统。

Actor的特征:

Ø ActorModel是消息传递模型,基本特征就是消息传递

Ø 消息发送是异步的,非阻塞的

Ø 消息一旦发送成功,不能修改

Ø Actor之间传递时,自己决定决定去检查消息,而不是一直等待,是异步非阻塞的

什么是Akka

Akka 是一个用 Scala 编写的库,用于简化编写容错的、高可伸缩性的 Java 和Scala 的 Actor 模型应用,底层实现就是Actor,Akka是一个开发库和运行环境,可以用于构建高并发、分布式、可容错、事件驱动的基于JVM的应用。使构建高并发的分布式应用更加容易。

spark1.6版本之前,spark分布式节点之间的消息传递使用的就是Akka,底层也就是actor实现的。1.6之后使用的netty传输。

2. 例:Actor简单例子发送接收消息


import scala.actors.Actor
class myActor extends Actor{
 
 def act(){
 while(true){
      receive {
 case x:String => println("save String ="+ x)
 case x:Int => println("save Int")
 case _ => println("save default")
      }
    }
  }
}
 
object Lesson_Actor {
 def main(args: Array[String]): Unit = {
 
    //创建actor的消息接收和传递
 val actor =new myActor()
    //启动
    actor.start()
    //发送消息写法
    actor ! "i love you !"
 
  }
}

3. 例:Actor与Actor之间通信

case class Message(actor:Actor,msg:Any)
 
class Actor1 extends Actor{
 def act(){
 while(true){
      receive{
 case  msg :Message => {
          println("i sava msg! = "+ msg.msg)
 
          msg.actor!"i love you too !"
          }
 case msg :String => println(msg)
 case  _ => println("default msg!")
      }
    }
  }
}
 
class Actor2(actor :Actor) extends Actor{
  actor ! Message(this,"i love you !")
 def act(){
 while(true){
	receive{
 case msg :String => {
 if(msg.equals("i love you too !")){
  	    println(msg)
  	   actor! "could we have a date !"
  	  }
  	}
 case  _ => println("default msg!")
	}
	}
	}
}
 
object Lesson_Actor2 {
 def main(args: Array[String]): Unit = {
 val actor1 = new Actor1()
    actor1.start()
 val actor2 = new Actor2(actor1)
    actor2.start()
  }
}

WordCount

import org.apache.spark.SparkConf
import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.rdd.RDD.rddToPairRDDFunctions
 
object WordCount {
 def main(args: Array[String]): Unit = {
 val conf = new SparkConf()
    conf.setMaster("local").setAppName("WC")
 val sc = new SparkContext(conf)
 val lines :RDD[String] = sc.textFile("./words.txt")
 val word :RDD[String]  = lines.flatMap{lines => {
 lines.split(" ")
    }}
 val pairs : RDD[(String,Int)] = word.map{ x => (x,1) }
 val result = pairs.reduceByKey{(a,b)=> {a+b}}
    result.sortBy(_._2,false).foreach(println)
 
    //简化写法
 lines.flatMap { _.split(" ")}.map { (_,1)}.reduceByKey(_+_).foreach(println)
 
  }
}

部分代码补充:

样例类

case class Person1(name:String,age:Int)
 
object Lesson_CaseClass {
 def main(args: Array[String]): Unit = {
 val p1 = new Person1("zhangsan",10)
 val p2 = Person1("lisi",20)
 val p3 = Person1("wangwu",30)
 
 val list = List(p1,p2,p3)
    list.foreach { x => {
      x match {
 case Person1("zhangsan",10) => println("zhangsan")
 case Person1("lisi",20) => println("lisi")
 case _ => println("no match")
      }
    } }
 
  }
}

模式匹配

object Lesson_Match {
 def main(args: Array[String]): Unit = {
 val tuple = Tuple6(1,2,3f,4,"abc",55d)
 val tupleIterator = tuple.productIterator
 while(tupleIterator.hasNext){
      matchTest(tupleIterator.next())
    }
 
  }
  /**
   * 注意点:
   * 1.模式匹配不仅可以匹配值,还可以匹配类型
   * 2.模式匹配中,如果匹配到对应的类型或值,就不再继续往下匹配
   * 3.模式匹配中,都匹配不上时,会匹配到 case _ ,相当于default
   */
 def matchTest(x:Any) ={
    x match {
 case x:Int=> println("type is Int")
 case 1 => println("result is 1")
 case 2 => println("result is 2")
 case 3=> println("result is 3")
 case 4 => println("result is 4")
 case x:String => println("type is String")
//      case x :Double => println("type is Double")
 case _ => println("no match")
    }
  }
 
}

trait 特性

trait Read {
 val readType = "Read"
 val gender = "m"
 def read(name:String){
	println(name+" is reading")
  }
}
 
trait Listen {
 val listenType = "Listen"
 val gender = "m"
 def listen(name:String){
	println(name + " is listenning")
  }
}
 
class Person() extends Read with Listen{
 override val gender = "f"
}
 
object test {
 def main(args: Array[String]): Unit = {
 val person = new Person()
    person.read("zhangsan")
    person.listen("lisi")
    println(person.listenType)
    println(person.readType)
    println(person.gender)
 
  }
}

object Lesson_Trait2 {
 def main(args: Array[String]): Unit = {
 val p1 = new Point(1,2)
 val p2 = new Point(1,3)
    println(p1.isEqule(p2))
    println(p1.isNotEqule(p2))
  }
}
 
trait Equle{
 def isEqule(x:Any) :Boolean
 def isNotEqule(x : Any)  = {
    !isEqule(x)
  }
}
 
class Point(x:Int, y:Int) extends Equle {
 val xx = x
 val yy = y
 
 def isEqule(p:Any) = {
    p.isInstanceOf[Point] && p.asInstanceOf[Point].xx==xx
  }
 
}

学习指南

​RUNOOB菜鸟教程 Scala 教程 https://www.runoob.com/scala/scala-tutorial.html

Scala 开发教程_w3cschool https://www.w3cschool.cn/scaladevelopmentguide/

官方教程 https://docs.scala-lang.org/zh-cn/tour/tour-of-scala.html

PlayScala社区https://scalacn.cool/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值