青蓝
四川大学·2022届

腾讯二面

二面小哥哥声音太温柔了 整个过程都轻声细语,面试体验太好了 全程就围绕一个问题就是一个抢红包的系统 如何设计,如何优化,如何处理安全问题 最后还问了一些一致性哈希和分布式的问题 全程一个半小时 许愿一个好结果!!!!!
分享
2
超好运许愿池
张姆斯
武汉科技大学·2022届

美团产品三轮面经+许愿hr面顺利

美团产品各业务部门面试轮次不一样,我是基础技术平台的,业务面3面+HR 时间线:8.22笔试,8.26一面,8.27二面,9.1三面,9.7HR面,被捞之后每轮节奏很紧、进度很快 8.26号下午,一面50min 面试官风格比较硬核但很专业 1. 对简历上的所有提过的数据深挖!一定要搞清楚所有数据背后的逻辑还有意义,以及项目本身和产品的一切基本相关信息,包括月活日活付费用户等等,都有可能被问到 2. 对简历提到的所有内容深挖,包括校园的创业经历和辩论队经历 (比较细节的是还考察了印象最深的一道辩题和我的持方和我的观点思路) 个人经历深挖,包括为什么想做产品经理,想做什么方向的,如何理解2B、2C等等 3. 两道case题:一道费米——统计望京商区所有小龙虾店家的数量 一道策略——已知机型手机号,美团外卖如何找到用户群体中的大学生群体并给他们打标签 用户群体包括:美团用户or其他/美团产品用户,不局限于外卖用户 4. 反问 看上去很少,但其实由于在被不断追问,有一点点压力,脑子也在飞速转动,最后面了50min左右结束 反问环节我询问了这个岗位具体是做什么的,面试官超级耐心给我讲了10分钟,包括他们做什么和想要什么样的人才 二面 挖了半小时简历,但跟昨天的差不太多,昨天面试后复盘总结了,这次讲的比较顺; 对产品经理的认知 对风控策略产品经理的认知 觉得自己什么能力比较match 具体举例,之前经历过什么项目获得的能力可以帮助你在这块更好完成 其他没有了,今天的面试官很和蔼但是同样专业 三面 32分钟 聊人生+个人经历+创业经历+实习经历; 这一轮面试官应该是大佬级别的,整个过程比较愉快,氛围轻松,没有相关业务问题; 明天HR面,听说团团HR也会挂人的,许个愿吧 从六月开始准备了真的很久,希望有个好的结果
分享
5
原味笔面经
胡伟云
物流、供应链,全球化_招聘

我正在收简历,快来投递吧 职位描述 1、负责参与菜鸟各个业务相关产品的系统架构及研发; 2、协助产品梳理业务需求,产出业务系统架构设计方案; 3、独立完成项目的系统分析、设计,并主导完成详细设计和编码的任务,确保项目的进度和质量; 4、主动关注并学习新技术,并能够在实践中应用,帮助建设团队技术氛围。 任职要求: 1、三年及以上Java开发经验,编程基础扎实,熟悉io、多线程、集合等基础框架; 2、熟悉Web开发,熟练使用Spring等主流的开发框架; 3、熟悉Linux下的常用命令,熟练使用MySQL、Oracle等常用关系型数据库,熟悉主流的key-value存储系统; 4、熟悉常用设计模式,有大型分布式、高并发、高负载、高可用性系统设计开发经验; 5、善于思考,能独立分析和解决问题,责任心强,具备良好的团队合作精神和抗压能力,要有创业的激情和坚定的信念 职位关键词:JavaSQLSpringMySQLOracleLinux 工作地点:杭州
分享
评论
我这里招人
M311
西交利物浦大学·2022届

许愿百度offer

求一个百度的offer!
分享
3
超好运许愿池
真空中的球形鸡
东南大学·2022届

贝壳java开发

约的五点,四点半提前进入面试间,签到之后面试官就进来了(之前没有签到过,以为只是双方掌握一下情况),自己还没准备好,跟面试官说五点,五点进去发现面试官去面别人了,接下来就是等待着。。。 下午七点开始,不到九点三面结束,贝壳的效率真高! 一面知识点+项目,问题切换很快 二面纯项目都没有让自我介绍,最后给了很大的肯定,感谢面试官! hr是个漂亮小姐姐,问对贝壳的了解,吸引你的地方,优缺点,有没有其他offer。。。 许愿offer! 许愿offer!! 许愿offer!!!
分享
评论
超好运许愿池
周岳
武汉科技大学·2022届

(ಥ㉨ಥ)有没有招聘板块hr或者参与过招聘笔...

总公司要求分公司招聘环节必须要有面试和笔试,但是我们招聘的要求并没有特别严格,所以笔试其实只需要有一个形式就可以了。我们目前的笔试是excel操作,对于筛选人才其实并没有什么太大作用,操作起来又非常麻烦。想问问大家有参加过哪些笔试?什么类型?可不可以留下对应的行业。
分享
1
小小酥
中南大学·2022届

腾讯游戏发行许愿贴

到三面总监面了,听说许愿都很灵,来试一下,盼早日上岸
分享
评论
超好运许愿池
园长
杭州电子科技大学·2022届

许愿字节意向
分享
1
超好运许愿池
小翻译小虎
中央财经大学·2022届

大数据 Scala 语言笔记

Scala 语言学习笔记 概述 Scala 简介: Scala 是一门基于 JVM 的多范式编程语言,通俗的说:Scala 是一种运行在 JVM 上的函数式的面向对象语言,之所以这样命名是因为它的设计目标是:随着用户的需求一起成长。Scala 可被广泛应用于各种编程任务,从编写小型的脚本到构建巨型系统都能胜任。正因如此,Scala 得以提供一些出众的特性,例如:它集成了面向对象编程和面向函数式编程的各种特性,以及更高层的并发模型。 Scala 语言的特点: 兼容性 兼容 Java,可以访问庞大的 Java 类库,例如操作 mysql、redis 等。 精简的 Scala 表达能力强,一行代码抵得上多行 Java 代码,开发速度快。 高级的 Scala 可以让程序保持短小、清晰,看起来更简洁、优雅。 静态类型的 Scala 拥有非常先进的静态类型系统,支持类型推断和模式匹配等。 可以开发大数据应用程序 例如 spark 、flink 程序等。 Scala 程序和 Java 程序的对比: Java 源代码通过 Javac 编译,编译结果为 Java 字节码、Java 类库 Scala 源代码通过 scalac 编译,编译结果为 Java 字节码、Java 类库、Scala 类库 使用 Scala 语言创建一个学生类,定义姓名和年龄两个属性,创建一个学生类对象并输出: 复制代码 1 2 3 4 5 6 //创建学生类 case class Student(var name:String, var age:Int) //创建学生对象 val s = Student("sjh", 24) //输出学生对象 print(s) 环境搭建: JDK Scala SDK 下载地址:https://www.scala-lang.org/download/ IDEA 在 plugins 中安装 Scala 插件(插件要与 IDEA 版本一致) 下载地址:https://plugins.jetbrains.com/plugin/1347-scala/versions Scala 解释器: Scala 解释器就像 Linux 命令一样,执行一条代码马上就可以看到执行结果。 启动解释器:win + R,输入 scala 即可。 打印 hello world: 复制代码 1 println("hello world") 退出解释器: 复制代码 1 :quit 小案例: 提示用户输入一句话,并把它打印出来: 复制代码 1 2 3 4 5 6 7 8 scala> import java.util.Scanner//导包 import java.util.Scanner   scala> println("输入你想说的一句话:")//提示用户 输入你想说的一句话:   scala> println("你想说的一句话是:"+ new Scanner(System.in).nextLine())//将用户输入输出 你想说的一句话是:我正在学Scala 基本语法 输出和分号 换行输出: 复制代码 1 println(1,2,3) 不换行输出: 复制代码 1 print(1,2,3) 注意:可以同时打印多个值,使用逗号隔开。 复制代码 1 2 println("hello scala")//单行分号可以不写 println("hello"); println("scala")//多行代码写在一行中间分号不能省略,最后一条代码的分号可省略。 常量 指程序运行过程中值不能发生改变的量。 字面值常量 复制代码 1 2 3 4 5 6 print(10) //整形常量 print(10.1) //浮点型常量 print("scala") //字符串常量 print('a') //字符常量 print(true, false) //布尔常量 print(null) //空常量 自定义常量 变量 格式: 复制代码 1 val/var 变量名:变量类型 = 初始值 val 定义的是不可重新赋值的变量,也就是自定义常量。 var 定义的变量可以被重新赋值。 可以使用类型推断来定义变量,代码更简洁: 复制代码 1 2 var name:String = "sjh" var name = "sjh" 字符串 Scala 提供多种定义字符串的形式 使用双引号 复制代码 1 var name = "sjh" 使用插值表达式,有效避免大量字符串拼接 复制代码 1 val/var 变量名 = s"{变量/表达式}字符串" 实例:定义三个变量,分别保存姓名,年龄,性别,定义一个字符串保存这些信息 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 scala> val name = "sjh" //定义姓名 name: String = sjh   scala> val age = 24 //定义年龄 age: Int = 24   scala> val sex = "male" //定义性别 sex: String = male   scala> val res = s"name=${name},age=${age},sex=${sex}" //保存信息 res: String = name=sjh,age=24,sex=male   scala> print(res) //输出 name=sjh,age=24,sex=male 使用三引号,可以保存大量文本,例如大段 SQL 语句,三引号中的所有内容都会作为字符串的值 复制代码 1 val/var 变量名 = """  字符串的值  """ 惰性赋值 在大数据开发中有时会编写非常复杂的 SQL 语句,当一些变量保存的数据较大时,而这些数据又不需要马上加载到 JVM 中,可以使用惰性赋值来提高效率。 复制代码 1 lazy val/var 变量名 = 值 标识符 标识符就是给变量、方法、类起名字的,Scala 和 Java 中的标识符非常相似。 命名规则: 必须由 大小写英文字母、数字、下划线_、美元符号$ 四部分任意组合。 数字不能开头。 不能和 Scala 关键字重名。 最好做到见名知意。 命名规范: 变量或方法:小驼峰命名,从第二个单词开始每个单词首字母大写。 类或特质:大驼峰命名,每个单词的首字母都大写。 包:全部小写,一般是公司域名反写,多级包用.隔开。 数据类型 Scala 也是一门强类型语言,它里面的数据类型绝大多数与 Java 一样。 基础类型 类型说明 Byte 8 位带符号整数 Short 16 位带符号整数 Int 32 位带符号整数 Long 64 位带符号整数 Char 16 位无符号 Unicode 字符 String Char 类型的序列,字符串 Float 32 位单精度浮点数 Double 64 位单精度浮点数 Boolean true 或 false Scala 和 Java 类型的区别: 所有类型都以大写字母开头 整形使用 Int 而不是 Integer 定义变量可以不写类型,让编译器自动推断 默认整形是 Int,默认浮点型是 Double Scala 的类型关系图: Any 是所有类型的父类,相当于 Java 中的 Object 类。 AnyVal 是所有数值类型的父类,AnyRef 是所有引用类型的父类。 Unit 类似于 Java 中的 void,一般作为返回值。 Null 是所有引用类型的子类,只有一个实例 null。 Nothing 是所有数据类型的子类,不能创建该类型实例,一般结合异常使用。 类型转换 当 Scala 程序在进行运算或赋值时,范围小的数据类型会自动转换为范围大的数据类型值,然后再进行计算。 类型转换分为值类型转换和引用类型转换,值类型转换又分为自动类型转换和强制类型转换。 自动类型转换 范围小的数据类型值会自动转换为范围大的数据类型值,自动类型转换从小到大依次为: 复制代码 1 Byte -> Short -> Int -> Long -> Float -> Double 强制类型转换 将范围大的数据类型值通过一定格式转换为范围小的数据类型值(可能会造成精度缺失)。 格式: 复制代码 1 val/var 变量名:数据类型 = 具体的值.toXxx 例如: 复制代码 1 2 3 4 5 scala> var a:Int = 1 a: Int = 1   scala> var b:Short = a.toShort b: Short = 1 值类型和 String 类型的相互转换 值类型转 String 格式: 复制代码 1 2 val/var 变量名:String = 值类型 + "" val/var 变量名:String = 值类型.toString String 类型转值类型格式: 复制代码 1 val/var 变量名:值类型 = 字符串值.toXxx//如果转换Char要使用toCharArray 键盘录入 使用步骤: 导包 复制代码 1 import scala.io.StdIn 通过 stdIn.readXxx() 接收用户键盘录入的数据 接收字符串数据: 复制代码 1 StdIn.readLine() 接收整数数据: 复制代码 1 StdIn.readInt() 示例:提示用户输入字符串 复制代码 1 2 3 4 5 6 7 scala> import scala.io.StdIn import scala.io.StdIn   scala> print("输入一句话:") 输入一句话: scala> print("输入的是:"+StdIn.readLine()) 输入的是:scala 运算符 算数运算符 包括 +(加号)、-(减号)、*(乘号)、/(除号)、%(取余)。 Scala中没有 ++,--这两个运算符。 a % b,底层是 a - a/b * b Scala 中把字符串和整数数字 n 相乘相当于让字符串重复 n 次。 复制代码 1 2 scala> print("x"*3) xxx 赋值运算符 基本赋值运算符 = 扩展赋值运算符 +=、-=、*=、/=、%= 关系运算符 包括>、>=、<、<=、==、!= 最终结果一定是 true 或 false。 如果需要比较数据值,使用==或者!=,如果比较引用值需要使用 eq 方法。 复制代码 1 2 3 4 5 6 7 8 9 10 scala> val s1 = "a" s1: String = a   scala> val s2 = s1 + "" s2: String = a   scala> print(s1 == s2) true scala> print(s1.eq(s2)) false 逻辑运算符 包括 &&、||、! 最终结果一定是 true 或 false。 位运算符 包括&(按位与)、|(按位或)、^(按位异或)、~(按位取反)、<<(左移一位,相当于乘2)、>>(右移一位,相当于除以2) 位运算符只针对于整形数据,运算符操作的是数据的二进制补码形式。 流程控制 顺序结构 程序按照从上至下、从左至右的顺序依次逐行执行,中间没有任何判断和跳转。 顺序结构是 Scala 中的默认流程结构。 选择结构 if 注意事项: 和 Java 一样,如果大括号内只有一行代码可省略大括号 条件表达式有返回值 没有三元表达式,可以使用 if-else 代替 复制代码 1 2 scala> println(if(1==1) 1 else 0) 1 块表达式: 使用一对大括号表示一个块表达式,块表达式也是有返回值的,最后一个表达式的值就是返回值 复制代码 1 2 3 4 5 6 scala> val n = {      | println(1)      | 1+2      | } 1 n: Int = 3 循环结构 for 循环 复制代码 1 2 3 for(i <- 表达式/数组/集合){     //逻辑 } 例如:打印10次 "hello scala" 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 scala> val n = 1 to 10 n: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)   scala> for( i <- n){      | println("hello scala")      | } hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala hello scala 守卫:for 表达式中的 if 判断语句。 例如输出1 - 10 之间的偶数: 复制代码 1 2 3 4 5 6 scala> for(i <- 1 to 10 if i % 2 == 0 ) println(i) 2 4 6 8 10 推导式:Scala 中的 for 循环也有返回值,可以使用 yield 表达式构建出一个集合。 例如,生成一个10、20...100 的集合: 复制代码 1 2 scala> val set = for(i <- 1 to 10) yield i * 10 set: scala.collection.immutable.IndexedSeq[Int] = Vector(10, 20, 30, 40, 50, 60, 70, 80, 90, 100) while 循环 格式: 复制代码 1 2 3 4 5 初始化条件 while(判断条件){     //循环体     //控制条件 } 例如:打印 1-5 的数字 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 scala> var i = 1 i: Int = 1   scala> while(i <= 5){      | println(i)      | i += 1      | } 1 2 3 4 5 do-while 循环 复制代码 1 2 3 4 5 初始化条件 do{     //循环体     //控制条件 }while(判断条件) break 和 continue 在 Scala 中,移除了 break 和 continue 关键字 如果要使用,需要 scala.util.controle 包下的 Breaks 类的 breakable 和 break 方法 用法: 导包: 复制代码 1 import scala.util.control.Breaks._ 使用 breakable 将 for 表达式包起来 for 表达式中需要退出循环的地方,添加 break() 方法调用。 例如输出 1-10 的数字,遇到5退出: 复制代码 1 2 3 4 5 6 scala> breakable{      |   for( i <- 1 to 10){      |     if(i == 5) break() else print(i)      |   }      | } 1234 continue 的实现和 break 类似,不同的是需要使用 continue 的地方是用 breakable 将 for 表达式的循环体包起来即可。 例如输出 1-10 不能整除 3 的数字: 复制代码 1 2 3 4 5 6 scala> for(i <- 1 to 10){      |   breakable{      |     if(i % 3 == 0) break() else print(i)      |   }      | } 12457810 案例:打印九九乘法表 复制代码 1 2 3 4 5 6 7 8 9 10 11 for(row <- 1 to 9){     for(col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")     }     println() } 或 for(row <- 1 to 9;col <- 1 to row){     print(s"${col} x ${row} = ${col * row}\t")     if(row == col) println() } 方法和函数 方法 语法格式: 复制代码 1 2 3 def 方法名(参数名1:参数类型1, 参数名2:参数类型2...)[: 返回值类型] = {     //方法体 } 注意: 参数列表的参数类型不能省略 返回值类型可以省略,由 Scala 编译器自动推断 返回值可以不写 return ,默认就是块表达式的值 示例:定义一个方法用来获取两个整形数字的最大值并返回结果。 复制代码 1 2 3 4 5 def getMax(num1:Int, num2:Int): Int = {     return if(num1 >= num2) num1 else num2 } 或 def getMax(num1:Int, num2:Int) = if(num1 >= num2) num1 else num2 返回值的类型推断 当定义递归方法时,不能省略返回值的类型。 示例:定义一个方法求 5 的阶乘。 复制代码 1 2 def f(n:Int):Int = if(n == 1) n else n * f(n - 1) print(f(5)) 惰性方法 当记录方法返回值的变量被声明为 lazy 时,方法的执行将被推迟,直到我们再次使用该值时方法才会执行,像这样的方法就叫做惰性方法。 注意:lazy 不能修饰 var 类型的变量。 使用场景: 打开数据库连接 提升某些特定模块的启动时间 确保对象中的某些字段优先初始化 示例:定义一个方法获取两个整数和,使用惰性技术调用该方法,然后打印结果。 复制代码 1 2 3 4 5 6 7 8 scala> def add(num1:Int, num2:Int) = num1 + num2 add: (num1: Int, num2: Int)Int   scala> lazy val sum:Int = add(1,2) sum: Int = <lazy>   scala> print(sum) 3 方法参数 默认参数 定义方法时可以给参数一个默认值并调用无参方法,例如: 复制代码 1 2 def add(num1:Int = 1, num2:Int = 1) = num1 + num2 print(add())//2 带名参数 调用方法时可以指定参数的名称进行调用,例如 复制代码 1 2 3 def add(num1:Int = 1, num2:Int = 1) = num1 + num2 print(add(num1 = 2))//3 print(add(10))//11 变长参数 如果方法的参数是不固定的,可以将该方法的参数定义为变长参数。 格式: 复制代码 1 2 3 def 方法名(参数名:参数类型*)[: 返回值类型] = {     //方法体 } 一个方法有且只能有一个变长参数,并且变长参数要放到参数列表的最后面。 例如:定义一个方法计算 n 个数字的和。 复制代码 1 2 3 def getSum(nums:Int*) = nums.sum print(getSum())//0 print(getSum(1, 2, 3, 4))//10 方法调用方式 后缀调用法 与 Java 相同,格式: 复制代码 1 2 对象名.方法名(参数) 例如:Math.abs(-1) 中缀调用法 格式: 复制代码 1 2 对象名 方法名 参数 例如:Math abs -1 在 Scala 中所有的操作符都是方法,操作符是一个方法名是符号的方法。 花括号调用法 方法只有一个参数时才能使用花括号调用法。 例如: 复制代码 1 2 3 4 5 scala> Math.abs{      | print("求绝对值,结果是:")      | -1      | } 求绝对值,结果是:res30: Int = 1 无括号调用法 如果方法没有参数,可以省略方法后面的括号。 例如:定义一个无参方法打印"hello scala",使用无括号调用法 复制代码 1 2 def say() = print("hello scala") say//hello scala 如果方法的返回值类型是 Unit,这样的方法称为过程,过程的 = 可以省略不写,花括号不能省略: 复制代码 1 def say() { print("hello scala") } 函数 Scala 支持函数式编程,Spark/Flink 程序会大量使用函数。 定义 复制代码 1 val 函数变量名 = (参数名1:参数类型1, 参数名2:参数类型2...) => 函数体 函数是一个对象 类似于方法,函数也有参数列表和返回值 函数定义不需要使用 def 定义 无需指定返回值类型 示例:定义一个计算两个整数之和的函数。 复制代码 1 2 val getSum = (a:Int, b:Int) => a + b val sum = getSum(1, 2)//3 方法和函数的区别 方法属于类或者对象,在运行时会加载到 JVM 的方法区。 可以将函数对象赋值给一个变量,在运行时会加载到 JVM 的堆中。 函数是一个对象,继承自 FunctionN,函数对象有apply、curried、toString、tupled这些方法,方法则没有。 结论:在 Scala 中,函数是对象,而方法是属于对象的,可以理解为:方法归属于函数。 可以通过在方法后加上空格和下划线将其转为函数,例如定义一个求和方法并转为函数: 复制代码 1 2 3 def add(a:Int, b:Int):Int = a + b val func = add _ func(1, 2)//3 案例:打印nn乘法表 通过方法: 复制代码 1 2 3 4 5 6 def write(n:Int){     for(row <- 1 to n;col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")         if(row == col) println()     } } 通过函数: 复制代码 1 2 3 4 5 6 val func = (n:Int) => {     for(row <- 1 to n;col <- 1 to row){         print(s"${col} x ${row} = ${col * row}\t")         if(row == col) println()     } } 类和对象 类和对象 创建类和对象可以通过 class 和 new 关键字实现,用 class 创建类,用 new 创建对象。 示例:创建一个 Person 类,然后创建其对象并打印。 创建一个 Scala 项目,并创建一个 Object 类(Object 修饰的类是单例对象)。 在 object 类中添加 main 方法。 创建 Person 类,并在 main 方法中创建 Person 类的对象然后输出结果。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 //实体类 class Person {   } ---------------------------------------------- //测试类 object ClassDemo {     //main方法,作为程序主入口,所有代码执行都从这里开始   def main(args: Array[String]): Unit = {     //创建 Person 对象     val person = new Person()     //打印对象     println(person)   } } 如果类是空的,没有任何成员,可以省略{} 如果构造器参数为空,可以省略() 复制代码 1 2 3 4 5 6 7 8 9 10 11 //简写类和对象 object ClassDemo {     class Person     def main(args: Array[String]): Unit = {     val person = new Person     println(person)   }   } 成员变量 可以使用 var/val 定义成员变量,对象通过 对象名. 的方式访问成员变量。 示例:定义一个 Person 类,包含一个姓名和年龄字段,创建一个具体对象并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person{     var name = ""     var age = 0   }     def main(args: Array[String]): Unit = {     val person = new Person     person.name = "sjh"     person.age = 24     print(s"姓名:${person.name},年龄:${person.age}")   }   } 使用下划线初始化成员变量 在定义 var 类型的成员变量时,可以使用 _ 初始化成员变量。 val 类型的成员变量,必须要自己手动初始化。 例如: 复制代码 1 2 3 4 class Person{     var name:String = _     var age:Int = _ } 定义和访问成员方法 在 Scala 的类中,也是使用 def 定义方法。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class Person{     var name:String = _     var age:Int = _       def printHello(msg:String): Unit = print(msg)     }     def main(args: Array[String]): Unit = {     val person = new Person     print(person.printHello("hello scala"))   }   } 访问修饰符 在 Scala 中没有 public 关键字,没有被标记为 private 和 protected 的成员都是公共的。 Scala 中的权限修饰符只有:privat、private[this]、protected、默认。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 object ClassDemo {     class Person{     private var name:String = _     private var age:Int = _       //获取姓名     def getName:String = name     //设置姓名     def setName(name:String): Unit = this.name = name     //获取年龄     def getAge:Int = age     //设置年龄     def setAge(age:Int): Unit = this.age = age     }     def main(args: Array[String]): Unit = {     val person = new Person     person.setName("sjh")     person.setAge(24)   }   } 构造器 主构造器 语法: 复制代码 1 2 3 class 类名(var/val 参数名:类型 = 默认值,...){     //构造代码块 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class Person(var name:String = "sjh",var age:Int = 24){     }     def main(args: Array[String]): Unit = {     //空参     val p1 = new Person("s",2)     //全参     val p2 = new Person()     //指定参数     val p3 = new Person(age = 2)   }   } 辅助构造器 语法: 辅助构造器方法名必须叫 this。 复制代码 1 2 3 4 def this(参数名:类型,...){     //第一行需要调用主构造器或其他构造器     //构造器代码 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Customer(var name:String,var address:String){         def this(array: Array[String]) = {         this(array(0),array(1))       }   }     def main(args: Array[String]): Unit = {     //通过辅助构造器创建对象     val customer = new Customer(Array("sjh", "xi'an"))   }   } 单例对象 定义单例对象和定义类很像,就是把 class 换成 object。 格式: 复制代码 1 object 单例对象名{} 在 object 中定义的成员变量类似 Java 中的静态变量,在内存中只有一个对象。 单例对象中,可以直接使用 单例对象名.的方式调用成员。 例如: 复制代码 1 2 3 4 5 6 7 8 9 10 11 object ClassDemo {     object Dog{     val leg_num = 4   }     def main(args: Array[String]): Unit = {     print(Dog.leg_num)   }   } 单例对象中的方法类似 Java 中的静态方法 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 object ClassDemo {     object Dog{     val leg_num = 4       def say(): Unit = print("dog")   }     def main(args: Array[String]): Unit = {     Dog.say()   }   } main 方法 在 Java 中 main 方法是静态的,Scala 中没有 main 方法,所以必须将其放在一个单例对象中。 创建单例对象 复制代码 1 2 3 4 5 6 7 object ClassDemo {     def main(args: Array[String]): Unit = {     print("hello scala")   }   } 继承 App 特质 复制代码 1 2 3 object ClassDemo extends App {     print("hello scala") } 伴生对象 在 Java 中有一些类会同时有静态内容和非静态内容,在 Scala 中想要实现类似效果可以使用伴生对象来实现。 一个 class 和 object 具有相同的名字,这个 object 被称为伴生对象,这个 class 被称为半生类。 伴生对象和半生类可以互相访问 private 属性,必须写在一个源文件。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 object ClassDemo {     //半生类,里面内容非静态   class Person{     def eat(): Unit = print("eat " + Person.food)   }     //伴生对象   object Person{     private val food = "rice"   }     def main(args: Array[String]): Unit = {     val person = new Person     person.eat()   }   } 如果某个成员变量权限为 private[this],表示只能在当前类访问,伴生对象也不能直接访问。 apply 方法 可以在创建对象时免去 new 操作,格式: 复制代码 1 2 3 object 伴生对象名{     def apply(参数名:参数类型...) = new 类(...) } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     //半生类   class Person(name:String, age:Int){   }     //伴生对象   object Person{     def apply(name:String, age:Int): Person = new Person(name, age)   }     def main(args: Array[String]): Unit = {     val person = Person("sjh", 24)   }   } 案例:定义工具类 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import java.text.SimpleDateFormat import java.util.Date   object DateUtils {     var sdf:SimpleDateFormat = _     //日期转字符串   def date2String(date:Date, template:String): String = {     sdf = new SimpleDateFormat(template)     sdf.format(date)   }     //字符串转日期   def string2Date(dateStr:String, template:String): Date = {     sdf = new SimpleDateFormat(template)     sdf.parse(dateStr)   }   } 继承和抽象类 继承 语法: 复制代码 1 2 3 class/object 子类 extends 父类{   } 子类重写方法必须使用 override 修饰,可以使用 override 重新一个 val 字段,父类的 var 字段不可重写。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 object ClassDemo {     class Person{     val name = ""     var age = 24       def say(): Unit = print("")   }     class Student extends Person{     override val name = "sjh"       override def say(): Unit = print("hello")   }     def main(args: Array[String]): Unit = {     val student = new Student()     student.say()//hello   }   } 类型判断 isInstanceOf 判断对象是否为指定类的对象 asInstanceOf 将对象转换为指定类型 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 object ClassDemo {     class Person{   }     class Student extends Person{     def say(): Unit = print("hello")   }     def main(args: Array[String]): Unit = {     val p:Person = new Student()     if(p.isInstanceOf[Student]) {       val s = p.asInstanceOf[Student]       s.say()     }   }   } isInstanceOf 只能判断对象是否为指定类以及其子类的对象而不能精确判断其类型,如果精确判断可以使用 getClass 和 classOf 来实现。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person{   }     class Student extends Person{   }     def main(args: Array[String]): Unit = {     val p:Person = new Student()     print(p.getClass == classOf[Person])//false     print(p.getClass == classOf[Student])//true   }   } 抽象类 如果类中有抽象字段或抽象方法,那么该类就必须是抽象类。 抽象字段:没有初始化的变量。 抽象方法:没有方法体。 格式: 复制代码 1 2 3 4 abstract class 抽象类名{     val/var 抽象字段名:类型     def 方法名(参数:参数类型...):返回类型 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object ClassDemo {     abstract class Shape{     val c:Int     def getArea:Double   }     class Square(x:Int) extends Shape{     override val c: Int = x       override def getArea: Double = c * c   }     class Circle(r:Int) extends Shape{     override val c: Int = r       override def getArea: Double = Math.PI * c * c   }     def main(args: Array[String]): Unit = {     val square = new Square(1)     println(square.getArea)//1     val circle = new Circle(1)     println(circle.getArea)//3.141592653589793   }   } 匿名内部类 匿名内部类是继承了类的匿名子类对象 语法: 复制代码 1 2 3 new 类名(){     //重写类中所有的抽象内容 } 如果类的主构造器参数列表为空,小括号可以省略。 作用:对象的成员方法仅调用一次、作为方法的参数传递。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     abstract class Person{     def sayHello()   }     def show(person: Person): Unit = person.sayHello()     def main(args: Array[String]): Unit = {     val person:Person = new Person {       override def sayHello(): Unit = println("hello")     }     show(person)   }   } 案例:动物类 定义抽象动物类,属性包括:姓名,年龄,行为:跑步和吃饭 定义猫类,重写吃饭方法,并定义独有抓老鼠方法。 定义狗类,重写吃饭方法,并定义独有看家方法。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 object ClassDemo {      abstract class Animal{     var name = ""     var age = 0       def run(): Unit = println("run")     def eat()   }     class Cat extends Animal{     override def eat(): Unit = println("eat fish")       def catchMouse(): Unit = println("catch mouse")   }     class Dog extends Animal{     override def eat(): Unit = println("eat meat")       def catchThief(): Unit = println("catch thief")   }       def main(args: Array[String]): Unit = {     val animal:Animal = new Cat()     if(animal.isInstanceOf[Cat]) {       val cat = animal.asInstanceOf[Cat]       cat.catchMouse()     } else if(animal.isInstanceOf[Dog]) {       val dog = animal.asInstanceOf[Dog]       dog.catchThief()     } else {       println("not cat or dog")     }   }   } 特质 概述 Scala 中的特质要用关键字 trait 修饰。 特点: 特质可以提高代码的复用性。 特质可以提高代码的扩展性和可维护性。 类与特质是继承关系,类与类只支持单继承,类与特质之间可以单继承也可以多继承。 Scala 的特质中可以有普通字段、抽象字段、普通方法、抽象方法。 如果特质只有抽象内容也叫瘦接口,如果既有抽象内容又有具体内容叫做富接口。 语法: 定义特质 复制代码 1 2 3 trait 特质名称{   } 继承特质 复制代码 1 2 3 class 类名 extends 特质1 with 特质2{   } 示例:类继承单个特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 object ClassDemo {     trait Logger{     def log(msg:String)   }     class ConsoleLogger extends Logger{     override def log(msg: String): Unit = println(msg)   }       def main(args: Array[String]): Unit = {     val logger = new ConsoleLogger     logger.log("hello scala")   }   } 示例:类继承多个特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 object ClassDemo {     trait MsgSender{     def send(msg:String)   }     trait MsgReceiver{     def receive()   }     class MsgWorker extends MsgSender with MsgReceiver{     override def send(msg: String): Unit = println(s"发送消息:$msg")       override def receive(): Unit = println("接收消息")   }     def main(args: Array[String]): Unit = {     val worker = new MsgWorker     worker.send("hello")     worker.receive()   }   } 示例:object 继承 trait 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     trait MsgSender{     def send(msg:String)   }     trait MsgReceiver{     def receive()   }     object MsgWorker extends MsgSender with MsgReceiver{     override def send(msg: String): Unit = println(s"发送消息:$msg")       override def receive(): Unit = println("接收消息")   }     def main(args: Array[String]): Unit = {     MsgWorker.send("hello scala")     MsgWorker.receive()   }   } 示例:trait 中的成员 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     trait Hero{     val name = ""     val arms = ""     def attack(): Unit = println("发起进攻")     def skill()   }     class Killer extends Hero{     override val name = "sjh"     override val arms = "gun"     override def skill(): Unit = println("kill")   }     def main(args: Array[String]): Unit = {     val killer = new Killer     killer.attack()     killer.skill()   }   } 对象混入 trait 在 Scala 中,类和特质之间无任何继承关系,但通过特定关键字让该类对象具有指定特质中的成员。 语法: 复制代码 1 val/var 对象名 = new 类 with 特质 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     trait Logger{     def log(): Unit = println("log..")   }     class User{     }     def main(args: Array[String]): Unit = {     val user = new User with Logger     user.log()//log..   }   } 使用 trait 实现适配器模式 当某个特质中有多个抽象方法,而我们只需要用到某个或某几个方法时不得不将该特质所有抽象方法重写。针对这种情况可以定义一个抽象类继承该特质,重写特质的所有方法,方法体为空。需要使用哪个方法只需要定义类继承抽象类,重写指定方法即可。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 object ClassDemo {     trait Play{     def mid()     def top()     def adc()     def jungle()     def support()   }      abstract class Player extends Play{      override def mid(): Unit = {}        override def top(): Unit = {}        override def adc(): Unit = {}        override def jungle(): Unit = {}        override def support(): Unit = {}    }     //新手类   class GreenHand extends Player {     override def support(): Unit = println("我是辅助")   }     def main(args: Array[String]): Unit = {     val player = new GreenHand     player.support()   }   } 使用 trait 实现模板方法模式 在 Scala 中我们可以先定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该结构的情况下重定义该算法的某些特定步骤,这就是模板方法设计模式。 优点:扩展性强、符号开闭原则。 缺点:类的个数增加会导致系统庞大,设计更抽象、增加代码阅读难度。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 object ClassDemo {     //模板类,计算某个方法的执行时间   abstract class Template{     def code()       def getRuntime: Long = {       val startTime = System.currentTimeMillis()       code()       val endTime = System.currentTimeMillis()       endTime - startTime     }   }     class Concrete extends Template{     override def code(): Unit = for(_ <- 1 to 10000) println("scala")   }     def main(args: Array[String]): Unit = {     println(s"耗时:${new Concrete().getRuntime} ms")   }   } 使用 trait 实现责任链模式 多个 trait 中出现了同一方法,且该方法最后都调用了 super.该方法名(),当类继承了这多个 trait 后就可以依次调用多个 trait 中的此同一个方法了,这就形成了一个调用链。 执行顺序:从右至左、先子类后父类。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 object ClassDemo {     trait Handler{     def handle(data:String): Unit = {       println("具体的处理数据...4")       println(data)     }   }     trait DataValid extends Handler{     override def handle(data: String): Unit = {       println("验证数据 3")       super.handle(data)     }   }     trait SignValid extends Handler{     override def handle(data: String): Unit = {       println("验证签名 2")       super.handle(data)     }   }     class Payment extends DataValid with SignValid{     def pay(data:String): Unit = {       println("用户发起支付请求 1")       super.handle(data)     }   }     def main(args: Array[String]): Unit = {     val payment = new Payment     payment.pay("发起转账..5")   }   } trait 构造机制 每个特质只有一个无参构造器 遇到一个类继承另一个类以及多个trait的情况,创建该类实例时构造器执行顺序: 执行父类构造器 从左到右依次执行 trait 的构造器 如果trait 有父 trait,先执行父 trait 如果多个 trait 有相同的父 trait,父 trait 构造器只初始化一次 执行子类构造器 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 object ClassDemo {     trait A{     println("A")   }     trait B extends A{     println("B")   }     trait C extends A{     println("C")   }     class D{     println("D")   }     class E extends D  with B with C{     println("E")   }     def main(args: Array[String]): Unit = {     new E//DABCE   }   } trait 继承 class trait 可以继承 class,会将所有的成员都继承下来。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class A{     def printMsg(): Unit = println("hello scala")   }     trait B extends A     class C extends B     def main(args: Array[String]): Unit = {     new C().printMsg()//hello scala   }   } 案例:程序员 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 object ClassDemo {     abstract class Programmer{     val name = ""     val age = 0       def eat(): Unit = println("eat")     def code()   }       class JavaProgrammer extends Programmer{     override def code(): Unit = println("精通 java")   }     trait BigData{     def bigData(): Unit = println("精通大数据")   }       class PartJavaProgrammer extends JavaProgrammer with BigData{     override def code(): Unit = {       super.code()       bigData()     }   }     def main(args: Array[String]): Unit = {     val javaProgrammer = new PartJavaProgrammer     javaProgrammer.code()   }   } 包 包 包就是文件夹,用 package 修饰,可以区分重名类。 作用域: 子包可以直接访问父包中的内容。 上层访问下层内容时,可以通过导包(import)或者写全包名的形式实现。 如果上下层有相同的类,使用时采用就近原则(优先使用下层)。 包对象: 要定义在父包中,一般用于对包的功能进行补充、增强。 可见性: 通过访问权限修饰符 private、protected、默认来限定访问修饰符。 格式: 复制代码 1 访问修饰符[包名] 引入: Scala 默认引入了 java.lang 包的全部内容,scala 包以及 Predef 包的部分内容。 包的引入不限于Scala 文件的顶不,而是可以编写到任何需要使用的地方。 如果需要导入某个包中的所有类和特质,使用下划线 _ 实现。 如果需要的时某个包的某几个类和特质,可以通过选取器 {}实现。 如果引入的多个包含有相同的类,可以通过重命名或隐藏解决。 重命名格式: 复制代码 1 import java.util.{HashSet => JavaSet} 隐藏格式: 复制代码 1 import java.util.{HashSet => _,_}//引入util包下除了HashSet的类 样例类 样例类是一种特殊类,一般用于保存数据,在并发编程以及 Flink 等框架中会经常使用。 格式: 复制代码 1 case class 样例类名([var/val] 成员变量名1:类型1...) 如果不写,变量默认修饰符是val。如果要实现某个成员变量值可以被修改,则需要手动添加var 修饰。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 object ClassDemo {     case class Person(val name:String, var age:Int)     def main(args: Array[String]): Unit = {     val person = new Person(name = "sjh", age = 24)     //person.name = "" 不可修改     person.age = 0   }   } 样例类的默认方法 apply 可以快速使用类名创建对象,省略 new 关键字。 toString 可以在打印时直接打印该对象各个属性值。 equals 可以直接使用 == 直接比较属性值。 hashCode 同一个对象哈希值一定相同,不同对象哈希值一般不同。 copy 可以用来快速创建属性值相同的实例对象,还可以使用带名参数的形式给指定的成员变量赋值。 unapply 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 object ClassDemo {     case class Person(var name:String, var age:Int)     def main(args: Array[String]): Unit = {     val person = Person(name = "sjh", age = 24)     println(person)//Person(sjh,24)     val person1 = person.copy(age = 20)     println(person1)//Person(sjh,20)   }   } 样例对象 用 case 修饰的单例对象就叫样例对象,而且它没有主构造器,主要用在: 枚举值 作为没有任何参数的消息传递 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     //特质 Sex,表示性别   trait Sex     //样例对象,表示男,继承 Sex 特质   case object Male extends Sex     //样例对象,表示女,继承 Sex 特质   case object Female extends Sex     //定义样例类 Person   case class Person(var name:String, var sex:Sex){}     def main(args: Array[String]): Unit = {     val p = Person("sjh", Male)   }   } 案例:计算器 定义样例类 Calculate,并在其中添加四个方法分别用来计算两个整数的加减乘除操作。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     case class Calculate(a:Int, b:Int){     def add(): Int = a + b     def sub(): Int = a - b     def mul(): Int = a * b     def div(): Int = a / b   }     def main(args: Array[String]): Unit = {     val res = Calculate(1, 1)     println(s"加法: ${res.add()}")//2     println(s"减法: ${res.sub()}")//0     println(s"乘法: ${res.mul()}")//1     println(s"除法: ${res.div()}")//1     }   } 数据结构 数组 定长数组 语法: 复制代码 1 2 val/var 变量名 = new Array[元素类型](数组长度) val/var 变量名 = new Array(元素1, 元素2 ...) 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val arr = new Array[Int](10)     arr(0) = 1     println(arr(0))//1     println(arr.length)//10 } 变长数组 语法: 复制代码 1 2 val/var 变量名 = ArrayBuffer[元素类型] val/var 变量名 = ArrayBuffer(元素1, 元素2 ...) 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val arr = ArrayBuffer[Int]()     val arr1 = ArrayBuffer("1", true, 3)     println(arr)//ArrayBuffer()     println(arr1)//ArrayBuffer(1, true, 3) } 增删改: 使用 += 添加单个元素 使用 -= 删除单个元素 使用 ++= 追加一个数组 使用 --= 移除多个元素 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val arr = ArrayBuffer("spark", "hadoop", "flink")     arr += "flume"     arr -= "spark"     arr ++= Array("hive", "sqoop")     arr --= Array("sqoop", "hadoop")     println(arr)//ArrayBuffer(flink, flume, hive) } 遍历数组 通过索引 复制代码 1 2 3 4 5 6 for(i <- 0 to arr.length-1)//to包括右     println(arr(i)) for(i <- arr.indices)     println(arr(i)) for(i <- 0 until(arr.length))//until不包括右     println(arr(i)) 通过 for 循环 复制代码 1 2 for (elem <- arr)       println(elem) 数组常用算法 sum :求和 max:求最大值 min:求最小值 sorted:排序,返回一个新的数组 reverse:反转,返回一个新的数组 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     val arr = Array(4,1,6,5,2,3)     println(arr.sum)//21     println(arr.max)//6     println(arr.min)//1     val arr1 = arr.sorted     for (elem <- arr1)     print(elem)//123456     println()     val arr2 = arr1.reverse     for (elem <- arr2)     print(elem)//654321 } 元组 元组一般用来存储不同类型的数据,并且长度和元素都不可变。 语法: 复制代码 1 2 3 4 //通过小括号实现 val/var 元组 = (元素1,元素2...) //通过箭头(只适用于有2个元素的情况) val/var 元组 = 元素1 -> 元素2... 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val tuple = ("sjh", 24)     val tuple1 = "sjh" -> 24     println(tuple)//(sjh,24)     println(tuple1)//(sjh,24) } 访问元组中元素 通过 元组名._编号 形式访问元组中元素,编号从 1 开始。或者通过 元组名.productIterator 获取迭代器遍历。 示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {     val tuple = "sjh" -> 24     //方法1 通过编号     println(tuple._1)     //方法2 获取迭代器     val iterator = tuple.productIterator     for (elem <- iterator)     println(elem) } 列表 不可变列表 List 存储的数据有序、可重复,有序是指元素的存入和取出顺序是一致的。列表分为不可变列表和可变列表。 不可变列表指的是列表的元素、长度都不可变。 语法: 复制代码 1 2 3 val/var 变量名 = List(元素1,元素2...) val/var 变量名 = Nil val/var 变量名 = 元素1 :: 元素2 :: Nil 可变列表 语法: 复制代码 1 2 val/var 变量名 = ListBuffer[数据类型]() val/var 变量名 = ListBuffer(元素1,元素2...) 可变列表常用操作: 格式 功能 列表名(索引) 根据索引获取元素 列表名(索引) = 值 修改元素值 += 添加单个元素 ++= 追加列表 -= 删除某个元素 --= 删除多个元素 toList 转为不可变列表 toArray 转为数组 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     val list = ListBuffer(1, 2, 3)     println(list(0))     list += 4     list ++= List(5, 6, 7)     list -= 7     list --= List(3, 4)     val list1 = list.toList     val array = list.toArray     println(list1)//List(1, 2, 5, 6)     for (elem <- array)  print(elem)//1256 } 列表常用操作 格式 功能 distinct 去重 isEmpty 判断是否为空 ++ 拼接两个列表 head 返回第一个元素 tail 返回除了第一个元素之外的其他元素 reverse 反转并返回新列表 take 获取前缀元素(自定义个数) drop 获取后缀元素(自定义个数) flatten 扁平化操作,返回新列表 zip 拉链操作,合并列表 unzip 拉开操作,拆分列表 toString 转换默认字符串 mkString 转换指定字符串 union 获取两个列表并集元素,返回新列表 intersect 获取两个列表交集元素,返回新列表 diff 获取两个列表差集元素,返回新列表 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4)     print(list.isEmpty)//false     val list2 = List(4, 5, 6)     val list3 = list ++ list2     println(list3)//List(1, 2, 3, 4, 4, 5, 6)     println(list3.head)//1     println(list3.tail)//List(2, 3, 4, 4, 5, 6)     //前3个是前缀     println(list3.take(3))//List(1, 2, 3)     //前3个是前缀,获取后缀     println(list3.drop(3))//List(4, 4, 5, 6) } 示例:扁平化操作 将嵌套列表(每个元素都是列表)的所有具体元素单独放到一个新的列表 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val list1 = List(1, 2)     val list2 = List(3, 4)     val list = List(list1, list2, List(5))     val flatten = list.flatten     println(list)//List(List(1, 2), List(3, 4), List(5))     println(flatten)//List(1, 2, 3, 4, 5) } 示例:拉链与拉开 拉链:将两个列表组合成一个元素为元组的列表 拉开:将一个包含元组的列表,拆解成包含两个列表的元组 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val names = List("sjh", "a", "bb")   val ages = List(24, 1, 10)   val list1 = names.zip(ages)   println(list1)//List((sjh,24), (a,1), (bb,10))   val tuple1 = list1.unzip   println(tuple1)//(List(sjh, a, bb),List(24, 1, 10)) } 示例:转换字符串 mkString 以指定符号分割元素 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4)   println(list.toString())//List(1, 2, 3, 4)   println(list.mkString(":"))//1:2:3:4 } 集 不可变集 特点:唯一、无序 语法: 复制代码 1 2 3 4 //创建空的不可变集 val/var 变量名 = Set[类型]() //指定元素 val/var 变量名 = Set(元素1, 元素2...) 常用操作: size 获取大小 遍历操作和数组一致 + 添加元素,生成一个新的 Set ++ 拼接集或列表,生成一个新的 Set - 删除一个元素,生成一个新的 Set -- 删除多个元素,,生成一个新的 Set 可变集 导入包 复制代码 1 import scala.collection.mutable.Set 映射 不可变 Map 语法: 复制代码 1 2 3 4 //通过箭头 val/var map = Map(k1->v1, k2->v2...) //通过小括号 val/var map = Map((k1,v1), (k2,v2)...) 可变 Map 导入包 复制代码 1 import scala.collection.mutable.Map 基本操作: map(key) 获取键对应值,不存在返回None map.keys 获取所有键 map.values 获取所有值 遍历 通过普通for实现 getOrElse 根据键获取值,不存在返回指定默认值 + 增加键值对,生成一个新的 Map。如果是可变 Map,直接使用 += 或 ++= 。 - 删除键值对,生成一个新的 Map。如果是可变 Map,直接使用 -= 或 --= 。 示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val map = Map("sjh" -> 24, "ax" -> 10)   println(map.keys)//Set(ax, sjh)   println(map.values)//HashMap(10, 24)   for (elem <- map) { println(elem)}//(ax,10) (sjh,24)   println(map.getOrElse("sjh", 1))//24   map += "abc" -> 10   println(map)//Map(abc -> 10, ax -> 10, sjh -> 24) } 迭代器 使用 iterator 从集合获取迭代器,迭代器的两个方法: hasNext 判断是否有下一个元素 next 返回下一个元素,没有会抛出异常 示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4, 5)     val iterator = list.iterator     while (iterator.hasNext)     print(iterator.next())//12345 } 函数式编程 函数式编程指 方法的参数列表可以接收函数对象。 函数名 功能 foreach 遍历集合 map 转换集合 flatmap 扁平化操作 sorted 默认排序 sortBy 按照指定字段排序 sortWith 自定义排序 groupBy 按指定条件分组 reduce 聚合计算 fold 折叠计算 foreach 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4, 5)   //函数格式 (函数参数列表) => {函数体}   list.foreach((x:Int) => {println(x)})   //简写格式1 通过类型推断省略参数数据类型   list.foreach(x => println(x))   //简写格式2 函数参数只在函数体出现一次,且函数体没有涉及复杂使用,可以使用下划线简化   list.foreach(println(_)) } map 将一种类型转换为另一种类型,例如将 Int 列表转为 String 列表 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     val list = List(1, 2, 3, 4)     //将数字转换为对应个数的 *     val list2 = list.map((x:Int) => {"*" * x})     println(list2)//List(*, **, ***, ****)     //根据类型推断简化     val list3 = list.map(x => "*" * x)     println(list3)//List(*, **, ***, ****)     //下划线     val list4 = list.map("*" * _)     println(list4)//List(*, **, ***, ****) } flatMap 可以理解为先进行 map ,再进行 flatten 操作。 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List("hadoop hive spark flink", "kudu hbase storm")     val list2 =list.map(_.split(" ")).flatten   println(list2)//List(hadoop, hive, spark, flink, kudu, hbase, storm)     val list3 =list.flatMap(_.split(" "))   println(list2)//List(hadoop, hive, spark, flink, kudu, hbase, storm) } filter 过滤出符合一定条件的元素,示例,筛选偶数: 复制代码 1 2 3 4 def main(args: Array[String]): Unit = {   val list = (1 to 6).toList   println(list.filter(_ % 2 == 0))//List(2, 4, 6) } 排序 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {     //升序排序     val list = List(3, 1, 2, 9, 8)     println(list.sorted)//List(1, 2, 3, 8, 9)     //指定字段排序     val list2 = List("01 hadoop", "02 flume", "03 hive")     println(list2.sortBy(_.split(" ")(1)))//List(02 flume, 01 hadoop, 03 hive)     //自定义排序实现降序     val list3 = List(2, 3, 1, 6, 4, 5)     //第一个下划线表示前面的元素,第二个下划线表示后面的元素     println(list3.sortWith(_ > _))//List(6, 5, 4, 3, 2, 1) } group by 将数据按指定条件进行分组,示例,按照性别分组: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     val list = List("sjh"->"男","ssf"->"女","ka"->"男")     //按照元素第二个元素分组     //val map = list.groupBy(x => x._2)     val map = list.groupBy(_._2)     println(map)//Map(男 -> List((sjh,男), (ka,男)), 女 -> List((ssf,女)))     //统计不同性别人数     val map2 = map.map(x => x._1 -> x._2.length)//不能用下划线简化,因为x在后面出现了2次     println(map2)//Map(男 -> 2, 女 -> 1) } reduce 和 fold 示例:计算1-10的和,reduce 相当于 reduceLeft,如果想从右到左计算使用 reduceRight 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val list = (1 to 10).toList     //x表示聚合操作的结果,y表示下一个元素     var i = list.reduce((x, y) => x + y)     //简化     i = list.reduce(_ + _)     println(i)//55 } fold 和 reduce 很像,只是 fold 多了一个指定初始化值参数 fold 相当于 foldLeft,如果想从右到左计算使用 foldRight 示例:定义一个列表包括1-10,假设初始化值100,计算所有元素和 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = (1 to 10).toList     //x表示聚合操作的结果,y表示下一个元素     val i = list.fold(100)(_ + _)     println(i)//155 } 案例:学生成绩单 定义列表,记录学生成绩,格式为:姓名,语文成绩,数学成绩,英语成绩。 获取所有语文成绩在60分以上得同学信息。 获取所有学生的总成绩。 按照总成绩降序排列。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def main(args: Array[String]): Unit = {     val list = List(("a", 37, 90 ,100), ("b", 90, 73 ,80), ("c", 60, 90, 76), ("d", 59, 21, 72), ("e", 100, 100, 100))     //获取语文成绩60分以上学生信息     val list1 = list.filter(_._2 > 60)     println(list1)//List((b,90,73,80), (e,100,100,100))       //获取所有学生总成绩     val list2 = list.map(x => x._1 -> (x._2 + x._3 + x._4))     println(list2)//List((a,227), (b,243), (c,226), (d,152), (e,300))       //按照总成绩降序排列     val list3 = list2.sortWith(_._2 > _._2)     println(list3)//List((e,300), (b,243), (a,227), (c,226), (d,152))   } 模式匹配、偏函数、异常、提取器 模式匹配 作用:判断固定值、类型查询、快速获取数据 简单模式匹配 格式: 复制代码 1 2 3 4 5 6 变量 match{     case 常量1 => 表达式1     case 常量2 => 表达式2     case 常量3 => 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     println("输入一个单词")     val word = StdIn.readLine()     word match {         case "hadoop" => println("大数据分布式存储和计算框架")         case "zookeeper" => println("大数据分布式协调服务框架")         case "spark" => println("大数据分布式内存计算框架")         case _ => println("未匹配")     } } 匹配类型 格式: 复制代码 1 2 3 4 5 6 对象名 match{     case 变量名1:类型1 => 表达式1     case 变量名2:类型2 => 表达式2     case _:类型3 => 表达式3//表达式没用到变量名可以使用下划线代替     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val a:Any = "hadoop"     a match {         case x:String => println(s"${x}是字符串")         case x:Int => println(s"${x}是数字")         case _ => println("未匹配")     } } 守卫 守卫指在 case 中添加 if 条件判断,这样可以让代码更简洁。 格式: 复制代码 1 2 3 4 5 6 变量 match{     case 变量名 if 条件1 => 表达式1     case 变量名 if 条件2 => 表达式2     case 变量名 if 条件3=> 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val a = StdIn.readInt()   a match {     case x if x > 0 => println("正数")     case x if x < 0 => println("负数")     case _ => println("是0")   } } 匹配样例类 要匹配的对象必须声明为 Any。 格式: 复制代码 1 2 3 4 5 6 对象名 match{     case 样例类型1(字段1, 字段2..) => 表达式1     case 样例类型2(字段1, 字段2..) => 表达式2     case 样例类型3(字段1, 字段2..) => 表达式3     case _ => 表达式4 //默认项 } 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     case class Customer(name:String, age:Int)     case class Order(id:Int)     def main(args: Array[String]): Unit = {     val a:Any = Customer("sjh", 20)     a match {       case Customer => println("是customer")       case Order => println("是order")       case _ => println("未匹配")     }   }   } 匹配集合 匹配数组 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {   //定义三个数组   val arr1 = Array(1, 2, 3)   val arr2 = Array(0)   val arr3 = Array(0 , 1, 2, 3,4)   arr1 match {     case Array(1, _, _) => println("长度为3,首元素为1")     case Array(0) => println("长度为1,元素0")     case Array(0, _*) => println("首元素0,其余任意")   } } 匹配列表 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def main(args: Array[String]): Unit = {     //定义三个列表     val list1 = List(1, 2, 3)     val list2 = List(0)     val list3 = List(0, 1, 2, 3,4)     list3 match {         case List(1, _, _) => println("长度为3,首元素为1")         case List(0) => println("长度为1,元素0")         case List(0, _*) => println("首元素0,其余任意")     }     //等价于     list2 match {         case 1 :: _ :: _ ::Nil => println("长度为3,首元素为1")         case 0 :: Nil => println("长度为1,元素0")         case 0 :: _ => println("首元素0,其余任意")     } } 匹配元组 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //定义三个元组     val a = (1, 2, 3)     val b = (3, 4, 5)     val c = (3, 4)     a match {         case (1, _, _) => println("长度为3,首元素为1")         case (_, _, 5) => println("长度为3,尾元素为5")         case _ => println("不匹配")     } } 变量声明中的模式匹配 在定义变量时,可以使用模式匹配快速获取数据 生成包含 0-10的数字,使用模式匹配分别获取第2、3、4个元素 生成包含 0-10的列表,使用模式匹配分别获取第1、2个元素 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     val arr = (0 to 10).toArray     val Array(_, x, y, z, _*) = arr     println(x, y, z)//(1,2,3)     val list = (0 to 10).toList     val List(a, b, _*) = list     val c :: d ::tail = list     println(a, b)//(0,1)     println(c, d)//(0,1) } 匹配 for 表达式 定义变量记录学生姓名和年龄,获取所有年龄为20的学生信息: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val map = Map("sjh" -> 20, "a" -> 21, "asx" -> 20)   //方式一 if   for((k, v) <- map if v == 20)     println(k, v)   //方式二 固定值   for((k, 20) <- map)     println(k, 20) } Option 类型 用来避免空指针异常,具体值使用 Some(x),空值使用 None 示例:定义一个两数相除的方法,使用 Option 类型封装结果 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 object ClassDemo {     def divide(a:Int, b:Int): Option[Int] = {     if(b == 0)       None     else       Some(a / b)   }     def main(args: Array[String]): Unit = {     divide(10, 0) match {       case None => println("除数不能为 0")       case Some(x) => println(s"结果为$x")     }   }   } 偏函数 可以配合集合的函数式编程简化代码。 偏函数是指 被包在花括号内没有 match 的一组 case语句。 示例: 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val pf:PartialFunction[Int, String] = {         case 1 => "一"         case 2 => "二"         case _ => "未匹配"     }     println(pf(1))//一 } 偏函数可结合 map 函数使用。 定义一个列表包含1-10的数字,将1-3的数字转为[1-3],4-8的数字转为[4-8],其余数字转为(8-*] 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = (1 to 10).toList   val list1 = list.map {     case x if x >= 1 && x <= 3 => "[1-3]"     case x if x >= 4 && x <= 8 => "[4-8]"     case _ => "(8,*]"   }   println(list1)//List([1-3], [1-3], [1-3], [4-8], [4-8], [4-8], [4-8], [4-8], (8,*], (8,*]) } 正则表达式 Scala 提供了 Regex 类定义正则表达式 要构造一个 Regex 对象直接使用 String 类的 r 方法即可 建议使用三个双引号表示正则表达式,不需要对其中的反斜杠转义。 格式: 复制代码 1 val 正则对象名 = """具体正则表达式""".r 示例:校验邮箱 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {     val regex = """.+@.+\.com""".r     val email = "sad@qq.com"     if(regex.findAllMatchIn(email).nonEmpty)     println("合法")     else     println("不合法") } 示例:过滤出不合法的邮箱 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val regex = """.+@.+\.com""".r   val emailList = List("sad@.com", "asda@qq.com", "***@,cn")   val list = emailList.filter((x) => regex.findAllMatchIn(x).isEmpty)   println(list)//List(sad@.com, ***@,cn) } 示例:获取邮箱运营商 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     //括号可以充当分组角色,用来提取其中内容     val regex = """.+@(.+)\.com""".r     val emailList = List("sad@.com", "asda@qq.com", "***@,cn")     val list = emailList.map{         case x @ regex(company) => x -> company         case x => x -> "未匹配"     }     println(list)//List((sad@.com,未匹配), (asda@qq.com,qq), (***@,cn,未匹配)) } 异常处理 捕获异常 该方式处理完异常,程序会继续执行 抛出异常 该方式处理完异常,程序会终止执行 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     //捕获异常     try{         val i = 10 / 0     }catch {         case _:ArithmeticException => println("算术异常")         case _ => println("其他异常")     }finally {         println("一般用来释放资源")     }     //抛出异常     throw new Exception("发生异常") } 提取器 一个类如果要支持模式匹配,必须要实现一个提取器。 提取器就是指 unapply 方法。 样例类自动实现了 unapply 方法。 要实现提取器,只需要在该类的伴生对象中实现一个unapply 方法即可。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 object ClassDemo {     class Student(var name:String, var age:Int)     object Student{     //apply 根据给定字段将其封装为 Student 类型对象     def apply(name: String, age: Int): Student = new Student(name, age)       //unapply 根据传入的学生对象,获取其各个属性值     def unapply(s: Student): Option[(String, Int)] = {       if(s == null)         None       else         Some(s.name, s.age)     }   }     def main(args: Array[String]): Unit = {     val s = Student("sjh", 24)     //获取 s 的属性     //通过 unapply     println(Student.unapply(s))     //通过模式匹配 需要实现 unapply方法     s match {       case Student(name, age) => println(s"$name,$age")       case _ => println("未匹配")     }   }   } 案例:随机职业 提示用户录入一个数字(1-5),然后根据数字打印出他的工作。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   println("请输入一个数字,1-5:")   val num = StdIn.readInt()   num match {     case 1 => println("BAT offer")     case 2 => println("BAT offer")     case 3 => println("BAT offer")     case 4 => println("BAT offer")     case 5 => println("BAT offer")     case _ => println("在家科研,哪都别去")   } } 数据的读写 读取数据 在 Source 单例对象中提供了一些获取数据的方法。 按行读取 以行为单位,返回值是一个迭代器类型的对象,通过toArray、toList方法将数据放到数组或列表。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")//在项目中创建一个 data目录和对应文件     //以行为单位读取数据     val lines:Iterator[String] = source.getLines()     //将读取到的数据封装到 List 集合     val list:List[String] = lines.toList     //打印结果     for(data <- list)     println(data)     //关闭 Source     source.close() } 按字符读取 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")//默认使用utf-8     //以字符为单位读取数据     val buffered:BufferedIterator[Char] = source.buffered     //打印结果     while(buffered.hasNext)     print(buffered.next())//不能使用println     //关闭 Source     source.close() } 如果文件内容较少,可以直接把它读取到一个字符串中: 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")     //将数据读取到字符串     val string = source.mkString     //打印结果     println(string)     //关闭 Source     source.close() } 读取词法单元和数字 词法单元指 以特定符号间隔开的字符串 创建一个文本文件 复制代码 1 2 3 10 2 5 11 2 5 1 3 2 读取所有整数,将结果加1并打印 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {     //创建 Source 对象,关联数据源文件     val source = Source.fromFile("./data/1.txt")     //将数据读取到字符串数组 \s 表示空白字符(空格,\t,\r,\n等)     val strArr:Array[String] = source.mkString.split("\\s+")     val intArr:Array[Int] = strArr.map(_.toInt)     //打印结果     for (elem <- intArr) {print(elem + " ")}//11 3 6 12 3 6 2 4 3     //关闭 Source     source.close() } 从 URL 或其他源读取 从 URL 地址读取 复制代码 1 val source = Source.fromURL("http:www.baidu.com") 从字符串读取 复制代码 1 val source = Source.fromString("字符串读取数据") 读取二进制文件 示例:读取图片 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   //创建File对象关联文件   val file = new File("./data/1.jpg")   //创建字节输入流   val fis = new FileInputStream(file)   val bytes = new Array[Byte](file.length().toInt)   //开始读取   val len = fis.read(bytes)   println(s"读取到的字节数:$len")   //关闭字节输入流   fis.close() } 写入数据 要使用 Java 的类库 往文件中写入指定内容 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   //创建字节输出流   val fos = new FileOutputStream("./data/1.txt")//目的地不存在会自动创建   //输出   fos.write("GetOffer".getBytes())   //关闭输出流   fos.close() } 序列化和反序列化 要实现序列化必须继承 Serializable 特质(标记接口),如果是样例类可以省略继承 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 case class Person(name:String, age:Int) [extends Serializable]   def main(args: Array[String]): Unit = {   val p = Person("sjh", 24)   //序列化   val outputStream = new ObjectOutputStream(new FileOutputStream("./data/2.txt"))   outputStream.writeObject(p)   outputStream.close()   //反序列化   val inputStream = new ObjectInputStream(new FileInputStream("./data/2.txt"))   val person = inputStream.readObject().asInstanceOf[Person]//读取出的对象是AnyRef,要转换   println(person)   inputStream.close() } 案例:学员成绩表 已知项目 data 文件夹下的 1.txt 记录了学生成绩如下: 复制代码 1 2 3 4 5 张三 37 90 100 李四 90 73 81 王五 60 90 76 赵六 89 21 72 田七 100 100 100 按照学生总成绩进行排名,按照姓名-语文成绩-数学成绩-英语成绩-总成绩的格式,输出到 2.txt 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 case class Student(var name:String,var chinese:Int, var math:Int, var english:Int){   def getSum:Int = chinese + math +english }   def main(args: Array[String]): Unit = {   //获取数据源文件   val source = Source.fromFile("./data/1.txt")   //封装到数组   val array:Iterator[Array[String]] = source.getLines().map(_.split(" "))   //定义可变列表存储学生信息   val stuList = ListBuffer[Student]()   //遍历数组,将数据封装成 Student 对象,添加到可变列表   for(s <- array){     stuList += Student(s(0), s(1).toInt, s(2).toInt, s(3).toInt)   }   //排序   val list = stuList.sortBy(_.getSum).reverse.toList   //通过字符输出流输出文件   val bw = new BufferedWriter(new FileWriter("./data/2.txt"))   bw.write("姓名 语文 数学 英语 总分")   bw.newLine()   for(s <- list){     bw.write(s"${s.name} ${s.chinese} ${s.math} ${s.english} ${s.getSum}")     bw.newLine()//换行   }   //关闭资源   bw.close()   source.close() } 2.txt: 复制代码 1 2 3 4 5 6 姓名 语文 数学 英语 总分 田七 100 100 100 300 李四 90 73 81 244 张三 37 90 100 227 王五 60 90 76 226 赵六 89 21 72 182 高阶函数 Scala 混合了面向对象和函数式特性,如果一个函数的参数列表可以接收函数对象,那么这个函数就被称为高阶函数。 作为值的函数 可以将函数对象传递给方法 。 需求:将一个整数列表中的每个元素转换为对应个数的*。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {     val list = (1 to 5).toList     val func = (x:Int) => "*" * x     val list1 = list.map(func)     println(list1)//List(*, **, ***, ****, *****) } 匿名函数 没有赋值给变量的函数就是匿名函数 复制代码 1 2 3 4 5 6 7 def main(args: Array[String]): Unit = {   val list = (1 to 5).toList   val list1 = list.map((x:Int) => "*" * x)   val list2 = list.map("*" * _)   println(list1)//List(*, **, ***, ****, *****)   println(list2)//List(*, **, ***, ****, *****) } 柯里化 柯里化指 将原先接收多个参数的方法转换为多个只有一个参数列表的过程 需求:定义方法完成两个字符串的拼接 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     //普通写法   def merge1(str1:String, str2:String): String = str1 + str2     //柯里化 f1表示函数   def merge2(str1:String, str2:String)(f1:(String, String) => String): String = f1(str1, str2)     def main(args: Array[String]): Unit = {     println(merge1("abc", "def"))//abcdef     println(merge2("abc", "def")(_ + _))//abcdef   }   } 闭包 闭包指 可以访问不在当前作用域范围数据的一个函数。(柯里化就是一个闭包) 通过闭包获取两个整数的和: 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {     val x = 10     val sum = (y:Int) => x + y     println(sum(10))//20 } 控制抽象 假设函数 A 的参数列表需要接收一个函数 B,而函数B没有输入值也没有返回值,那么函数A称为控制抽象函数。 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 object ClassDemo {     val func = (f1:() => Unit) => {     println("welcome")     f1()     println("bye")   }     def main(args: Array[String]): Unit = {     func(() => println("shopping.."))   }   } 结果: 复制代码 1 2 3 welcome shopping.. bye 案例:计算器 定义一个方法,用来完成两个 Int 类型数字的计算 具体计算封装到函数中 使用柯里化完成操作 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 object ClassDemo {     //普通写法   def add(a:Int, b:Int): Int = a + b   def sub(a:Int, b:Int): Int = a - b   def mul(a:Int, b:Int): Int = a * b   def div(a:Int, b:Int): Int = a / b     //柯里化   def calculate(a:Int, b:Int)(func:(Int,Int) => Int): Int = func(a, b)     def main(args: Array[String]): Unit = {     println(calculate(1, 1)(_ + _))//2     println(calculate(1, 1)(_ - _))//0     println(calculate(1, 1)(_ * _))//1     println(calculate(1, 1)(_ / _))//1     }   } 隐式转换和隐式参数 隐式转换 隐式转换指用 implicit 关键字 声明的带有 单个参数 的方法。该方法是被自动调用的,用来实现自动将某种类型的数据转换为另一种类型的数据。 示例:手动导入 通过隐式转换,让 File 类的对象具有 read 功能。 执行流程:file对象没有read方法 -> 有隐式转换 -> 将File转为RichFile对象 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     class RichFile(file: File){     //定义 read 方法     def read(): String = Source.fromFile(file).mkString   }     object Implicit{     implicit def file2RichFile(file: File): RichFile = new RichFile(file)   }     def main(args: Array[String]): Unit = {     //手动导入     import Implicit.file2RichFile     val file = new File("./data/1.txt")     file.read()   }   } 自动调用隐式转换: 当对象调用类中不存在的方法或成员时 当方法参数类型与目标类型不一致时 如果在当前作用域存在隐式转换方***自动导入隐式转换 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 object ClassDemo {     class RichFile(file: File){     //定义 read 方法     def read(): String = Source.fromFile(file).mkString   }     def main(args: Array[String]): Unit = {     //自动导入     implicit def file2RichFile(file: File): RichFile = new RichFile(file)       val file = new File("./data/1.txt")     file.read()   }   } 隐式参数 隐式参数指用 implicit 关键字 修饰的变量。调用方法时可以不给定初始值,因为编译器会自动查找缺省值。 使用步骤: 在方法后添加一个参数列表,参数使用 implicit 修饰 在 object 中定义 implicit 修饰的隐式值 调用该方法,可以不传入 implicit 修饰的参数值 和隐式转换一样,可以手动导入,如果作用域内定义了隐式值可以自动导入。 定义一个show方法,实现将传入的值,使用指定前缀分隔符和后缀分隔符包装起来。 例如 show("a")("<<",">>") // <<a>> 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 object ClassDemo {     //name表示姓名,第一个String表示前缀信息,第二个String表示后缀信息   def show(name:String)(implicit delimit:(String, String)): String = delimit._1 + name +delimit._2     //定义单例对象,用来给隐式参数默认值   object Implicit{     implicit val delimit_default: (String, String) = ("<<" ,">>")   }     def main(args: Array[String]): Unit = {     //手动导入     import Implicit.delimit_default     //调用show     println(show("abc"))//<<abc>>     println(show("abc")("<-", "->"))//<-abc->   }   } 自动导入 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     //name表示姓名,第一个String表示前缀信息,第二个String表示后缀信息   def show(name:String)(implicit delimit:(String, String)): String = delimit._1 + name +delimit._2     def main(args: Array[String]): Unit = {     //自动导入     implicit val delimit_default: (String, String) = ("<<" ,">>")     //调用show     println(show("abc"))//<<abc>>     println(show("abc")("<-", "->"))//<-abc->   }   } 案例:获取列表元素平均值 通过隐式转换,获取列表中所有元素的平均值。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 object ClassDemo {     class RichList(list: List[Int]){     def avg(): Option[Int] = {       if(list.isEmpty)         None       else         Some(list.sum / list.size)     }   }     def main(args: Array[String]): Unit = {     //自动导入     implicit def list2RichList(list: List[Int]): RichList = new RichList(list)     //调用     val list = (1 to 10).toList     println(list.avg())//Some(5)   }   } 递归 递归就是方法自己调用自己 示例:求阶乘 复制代码 1 2 3 4 5 6 7 8 9 object ClassDemo {     def f(n: Int): Int = if(n == 1) n else n * f(n - 1)     def main(args: Array[String]): Unit = {     println(f(5))   }   } 内存图解 Scala 中,内存分为五部分 栈 所有代码的执行、存储局部变量。 按照 FILO 的顺序执行,方法执行完毕后立马被回收。 堆 存储所有new 出来的对象。 在不确定的时间被垃圾收集器回收。 方法区 存储字节码文件,方法等数据。 程序执行完毕后,由操作系统回收资源。 本地方法区 和本地方法相关。 寄存器 和 CPU 相关。 斐波那契数列 已知数列1,1,2,3,5,8,13,求第12个数字。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     def f(n: Int): Int = {     if(n == 1 || n == 2)       1     else       f(n - 1) + f(n - 2)   }     def main(args: Array[String]): Unit = {     println(f(12))//144   }   } 案例:打印目录文件 定义 printFile 方法,该方法打印该文件夹下所有文件路径。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 object ClassDemo {     def printFile(dir: File): Unit = {     if(!dir.isDirectory)       println("路径不合法")     else {       //获取该目录下所有文件及文件夹       val files:Array[File] = dir.listFiles()       for(listFile <- files){         if(listFile.isDirectory)           printFile(listFile)         else           println(listFile)       }     }   }     def main(args: Array[String]): Unit = {     printFile(new File("d:/"))   }   } 泛型 泛型 泛型的意思是 泛指某种具体的数据类型,在 Scala 中泛型用 [数据类型] 表示。 泛型方法 示例,定义一个泛型方法,获取任意数据类型的中间元素 复制代码 1 def getMiddleElement[T](array: Array[T]): T = {array(array.length / 2)} 泛型类 示例,定义一个 Pair 泛型类,包含两个字段且字段类型不固定 复制代码 1 class Pair[T](var a:T, var b:T) 泛型特质 复制代码 1 2 3 4 5 6 7 8 9 10 11 trait Logger[T]{   val a:T     def show(b:T) }   object ConsoleLogger extends Logger[String]{   override val a: String = "sjh"     override def show(b: String): Unit = println(b) } 上下界 上界 使用 T <: 类型名 表示给类型添加一个上界,表示该类型必须是 T 或 T 的子类。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 object ClassDemo {     class Person     class Student extends Person     def demo[T <: Person](array: Array[T]): Unit = println(array)     def main(args: Array[String]): Unit = {     demo(Array(new Person))     demo(Array(new Student))     demo(Array("a"))//报错   }   } 下界 使用 T >: 类型名 表示给类型添加一个下界,表示该类型必须是 T 或 T 的父类。 如果泛型既有上界又有下界,下界写在前面,[T >: A <: B] 协变、逆变、非变 协变:类 A 和 类 B 之间是父子类关系,Pair[A] 和 Pari[B] 之间也有父子关系。 复制代码 1 class Pair[+T]{} 逆变:类 A 和 类 B 之间是父子类关系,但 Pair[A] 和 Pari[B] 之间是子父关系。 复制代码 1 class Pair[-T]{} 非变:类 A 和 类 B 之间是父子类关系,Pair[A] 和 Pari[B] 之间没有任何关系。 复制代码 1 class Pair[T]{} //默认类型是非变的 示例: 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 object ClassDemo {     class Super     class Sub extends Super     class Temp1[T]     class Temp2[+T]     class Temp3[-T]     def main(args: Array[String]): Unit = {     //测试非变     val t1:Temp1[Sub] = new Temp1[Sub]     //val t2:Temp1[Super] = t1 报错     //测试协变     val t3:Temp2[Sub] = new Temp2[Sub]     val t4:Temp2[Super] = t3     //测试逆变     val t5:Temp3[Super] = new Temp3[Super]     val t6:Temp3[Sub] = t5   }   } 集合 分类: 可变集合 线程不安全 集合本身可以动态变化,且可变集合提供了改变集合内元素而都方法。 复制代码 1 scala.collection.mutable //需要手动导包 不可变集合 线程安全 默认类库,集合内的元素一旦初始化完成就不可再进行更改,任何对集合的改变都将生成一个新的集合。 复制代码 1 scala.collection.immutable //不需要手动导包 Set 无序、唯一 HashSet SortedSet TreeSet BitSet ListSet Seq 序列、有序、可重复、元素有索引 IndexedSeq 索引序列,随机访问效率高 NumericRange Range的加强 Range 有序整数序列,类似等差数列 Vector 通用不可变的数据结构,获取元素时间长,随机更新快于数组或列表 String 字符串 LinearSeq 线性序列,主要操作首尾元素 List 列表 Queue 队列 Stack 栈 不可变栈已经弃用 Stream 流 Map HashMap SortedMap TreeMap ListMap 可变集合比不可变集合更丰富,例如在 Seq 中,增加了 Buffer 集合,例如 ArrayBuffer 和 ListBuffer。 Traverable Traverable 是一个特质,它的子特质 immutable.Traverable 和 mutable.Traverable 分别是不可变集合和可变集合的父特质。 格式: 创建空的Traverable 对象。 复制代码 1 2 3 val t = Traverable.empty[Int] val t = Traverable[Int]() val t = Nil 创建带参数的Traverable 对象。 复制代码 1 2 val t = List(1, 2, 3).toTraverable val t = Traverable(1, 2, 3)//默认生成List 转置: 使用 transpose 方法。 转置操作时,需要每个集合的元素个数相同。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = Traversable(Traversable(1, 4, 7), Traversable(2, 5, 8), Traversable(3, 6, 9))   println(t1)//List(List(1, 4, 7), List(2, 5, 8), List(3, 6, 9))   val transpose = t1.transpose   println(transpose)//List(List(1, 2, 3), List(4, 5, 6), List(7, 8, 9)) } 拼接: ++ 可以拼接数据,但是会创建大量临时集合,可以通过 concat 方法实现。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = Traversable(1, 2, 3)   val t2 = Traversable(4, 5, 6)   val traversable = Traversable.concat(t1, t2)   println(traversable)//List(1, 2, 3, 4, 5, 6) } 筛选: 利用 collect 方法实现偏函数结合集合使用,从集合中筛选指定数据。 复制代码 1 2 3 4 5 6 7 8 9 10 11 def main(args: Array[String]): Unit = {   val t1 = (1 to 10).toList   def filter:PartialFunction[Int, Int] = {     case x if x % 2 == 0 => x   }   //val t2 = t1.collect(filter)   val t2 = t1.collect({     case x if x % 2 == 0 => x   })   println(t2)//List(2, 4, 6, 8, 10) } scan 方法 复制代码 1 def scan[B](z:B)(op: (B, B) => B) [B] 表示返回值的数据类型,(z:B)表示初始化值,(op: (B, B) => B)表示具体的函数运算。 示例:定义 traversable 集合,存储1-5,假设初始值为1,分别获取每个元素的阶乘值。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   //val seq = t1.scan(1)((a, b) => a * b)   val seq = t1.scan(1)(_ * _)   println(seq)//Vector(1, 1, 2, 6, 24, 120) } 获取集合指定元素 head/last : 获取第一个/最后一个元素,不存在抛出异常 headOption/lastOption : 获取获取第一个/最后一个元素,返回值是 Option find: 查找符号条件的第一个元素 slice :截取集合中的一部分元素,左闭右开 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   println(t1.head)//1   println(t1.last)//5   println(t1.headOption)//Some(1)   println(t1.lastOption)//Some(5)   println(t1.find(_ % 2 == 0))//Some(2)   println(t1.slice(0, 2))//Vector(1, 2) } 判断元素是否合法 forall 如果集合中所有元素都满足条件返回 true exist 如果集合中有一个元素满足条件返回 true 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {   val t1 = 1 to 5   println(t1.forall(_ % 2 == 0))//false   println(t1.exists(_ % 2 == 0))//true } 聚合函数 count 统计集合中满足条件的元素个数 sum 获取集合元素和 product 获取集合中所有元素成绩 max 获取集合中所有元素最大值 min 获取集合中所有元素最小值 集合类型转换 toList toSet toArray toSeq 填充元素 fill 快速生成指定数量的元素 iterator 根据指定条件,生成指定个数的元素 range 生成某个区间内的指定间隔的所有数据,不传间隔参数默认 1 复制代码 1 2 3 4 5 6 7 8 9 10 def main(args: Array[String]): Unit = {   val t1 = Traversable.fill(5)("a")   println(t1)//List(a, a, a, a, a)   val t2 = Traversable.fill(2, 2, 2)("a")   println(t2)//List(List(List(a, a), List(a, a)), List(List(a, a), List(a, a)))   val t3 = Traversable.iterate(1, 5)(_ * 10)   println(t3)//List(1, 10, 100, 1000, 10000)   val t4 = Traversable.range(1, 100, 7)   println(t4)//List(1, 8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99) } 案例:随机学生序列 定义一个 Traversable 集合,包含 5 个学生信息,学生姓名年龄随机生成。 按照学生年龄降序排列并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 object ClassDemo {     case class Student(name:String, age:Int)     def main(args: Array[String]): Unit = {     val names: List[String] = List("aa" ,"bb", "cc", "dd", "ee")     val r:Random = new Random()     val students = Traversable.fill(5)(Student(names(r.nextInt(names.size)), r.nextInt(10) + 20))     val list = students.toList     val list1 = list.sortWith(_.age < _.age)     println(list1)//List(Student(ee,22), Student(bb,23), Student(ee,23), Student(ee,24), Student(aa,26))   }   } Iterable Iterable 表示一个可以迭代的集合,它继承了 Travsersable 特质,同时也是其他集合的父特质。它定义了获取迭代器的方法,这是一个抽象方法。 遍历集合示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   val list = List(1, 2, 3, 4, 5)   //方式一 主动迭代   val iterator = list.iterator   while (iterator.hasNext)     print(iterator.next() + " ")   //方式二 被动迭代   list.foreach(x => print(x + " ")) } 分组遍历示例: 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val i = (1 to 5).toIterable   val iterator = i.grouped(2)   while (iterator.hasNext)     print(iterator.next() +" ")//Vector(1, 2) Vector(3, 4) Vector(5) } 按照索引生成元组: 复制代码 1 2 3 4 5 def main(args: Array[String]): Unit = {     val i = Iterable("A", "B", "C", "D", "E")     val tuples = i.zipWithIndex.map(x => x._2 -> x._1)     println(tuples)//List((0,A), (1,B), (2,C), (3,D), (4,E)) } 判断集合是否相同: 复制代码 1 2 3 4 5 6 7 def main(args: Array[String]): Unit = {   val i1 = Iterable("A", "B", "C")   val i2 = Iterable("A", "C", "B")   val i3 = Iterable("A", "B", "C")   println(i1.sameElements(i2))//false   println(i1.sameElements(i3))//true } Seq Seq 特质代表 按照一定顺序排列的元素序列,序列是一种特别的可迭代集合,它的特点是有序、可重复、有索引 创建 Seq 集合: 复制代码 1 2 3 4 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   println(seq)//Range(1, 2, 3, 4, 5) } 获取长度及元素: 通过 length 或 size 方法获取长度,通过索引直接获取元素。 复制代码 1 2 3 4 5 6 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   println(seq.length)//5   println(seq.size)//5   println(seq(0))//1 } 获取指定元素的索引值 indexOf 获取指定元素在列表中第一次出现的位置 lastIndexOf 获取指定元素在列表中最后一次出现的位置 indexWhere 获取满足条件的元素,在集合中第一次出现的索引 lastIndexWhere 获取满足条件的元素,在集合中最后一次出现的索引 indexOfSlice 获取指定的子序列在集合中第一次出现的位置 找不到返回 -1。 判断是否包含指定数据: startsWith 是否以指定子序列开头 endsWith 是否以指定子序列结尾 contains 判断是否包含某个指定数据 containsSlice 判断是否包含某个指定子序列 修改指定的元素: updated 修改指定索引位置的元素为指定的值。 patch 修改指定区间的元素为指定的值。 复制代码 1 2 3 4 5 6 7 8 def main(args: Array[String]): Unit = {   val seq = (1 to 5).toSeq   val seq1 = seq.updated(0, 5)   println(seq1)//Vector(5, 2, 3, 4, 5)   //参数1 起始索引 参数2 替换后的元素 参数3 替换几个   val seq2 = seq.patch(1, Seq(1, 2), 3)   println(seq2)//Vector(1, 1, 2, 4, 5) } Stack top 获取栈顶元素 push 入栈 pop 出栈 clear 清除所有元素 mutable.Stack 有一个独有方法 pushAll,把多个元素压入栈中。 ArrayStack 有独有方法为:dup,复制栈顶元素。preseving,执行表达式,执行完毕后恢复栈。 操作示例: 复制代码 1 2 3 4 5 6 7 8 9 def main(args: Array[String]): Unit = {   //从右往左入栈   val s = mutable.Stack(1, 2, 3, 4, 5)   println(s.top)//1   println(s.push(6))//Stack(6, 1, 2, 3, 4, 5)   println(s.pushAll(Seq(7, 8, 9)))//Stack(9, 8, 7, 6, 1, 2, 3, 4, 5)   println(s.pop())//9   println(s.clear())//() } 定义可变栈存储1-5,通过dup方法复制栈顶元素,通过preseving 方法先清空元素再恢复。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   //从右往左入栈   val s = mutable.ArrayStack(1, 2, 3, 4, 5)   //复制栈顶元素   s.dup()   println(s)//ArrayStack(1, 1, 2, 3, 4, 5)   s.preserving({     //该方法执行后,栈中数据会恢复     s.clear()   })   println(s)//ArrayStack(1, 1, 2, 3, 4, 5) } Queue 表示队列,特点是 FIFO,常用的队列是 mutable.Queue,内部以 MutableList 实现。 enqueue 入队 dequeue 出队 dequeueAll 移除所有满足条件的元素 dequeueFirst 移除第一个满足条件的元素 案例:统计字符个数 提示用户录入字符串并接受,统计每个字符出现的次数并打印。 复制代码 1 2 3 4 5 6 7 8 9 10 11 12 def main(args: Array[String]): Unit = {   println("请输入一个字符串:")   val str = StdIn.readLine()   val map = mutable.Map[Char, Int]()   for(c <- str.toCharArray){     if(!map.contains(c))       map += c -> 1     else       map += c -> (map.getOrElse(c, 1) + 1)   }   map.foreach(println(_)) }
分享
1
先马后看
卡哇伊娃
墨尔本大学·2022届

腾讯初面许愿

许愿腾讯初面! 今天下午面的初面,感觉聊的还挺好 求一个复试! --------- 复试结束,感觉是压力面 许愿复试通过!!!
分享
5
超好运许愿池
宁叔
江苏大学·2022届

许愿亿联二面过

今天才面试,感觉发挥不怎么好,求过求过,求offer
分享
3
超好运许愿池
Tomorrow
首都师范大学·2022届

校招全国统一模拟笔试(七月场)编程题参考代码

参考code #include <bits/stdc++.h> using namespace std; const int maxn = 200 + 5; int a[maxn], n, A; int main() { scanf("%d%d", &n, &A); for(int i = 0; i < n; i++) scanf("%d", &a[i]); for(int i = 0; i < n; i++) { if(a[i] == A) A += A; } printf("%d\n", A); return 0; } 黑化的牛牛 分析 一个做法是枚举去除掉的字符然后去重一下。 其实我们仔细观察对于相邻的两个字符如果一样去除掉后一个是不会产生新的字符串的,于是问题就转化为计算字符串当前字符是否和前面字符相同,特殊处理下长度等于1的情况即可。 参考code #include <bits/stdc++.h> using namespace std; string s; int main() { cin >> s; int ans = 0; for(int i = 1; i < s.size(); i++) { if(s[i] != s[i - 1]) ans++; } if(s.size() == 1) ans = 0; ans++; cout << ans << endl; return 0; } 黑白卡片 分析 考虑最终的状态只有两种,然后分别比较之后取最小值即可。 参考code #include <bits/stdc++.h> using namespace std; string s; int main() { cin >> s; int cnt1 = 0, cnt2 = 0; for(int i = 0; i < s.size(); i++) { if(i % 2 == 0) { if(s[i] != 'W') cnt1++; } else { if(s[i] != 'B') cnt1++; } } for(int i = 0; i < s.size(); i++) { if(i % 2 == 0) { if(s[i] != 'B') cnt2++; } else { if(s[i] != 'W') cnt2++; } } cout << min(cnt1, cnt2) << endl; return 0; } 序列交换 分析 用vector存序列,枚举交换之后丢进set去重得到个数即可。 参考code #include <bits/stdc++.h> using namespace std; int n; set<vector <int> > s; vector<int> x; int main() { cin >> n; for(int i = 0; i < n; i++) { int tmp; cin >> tmp; x.push_back(tmp); } for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { if(i != j) { swap(x[i], x[j]); s.insert(x); swap(x[i], x[j]); } } } cout << s.size() << endl; return 0; } 丑陋的字符串 分析 前缀都是'?'部分都是有方案可以抵消掉的。。后面的部分遇到'?'考虑前一个是什么贪心放就好了。 参考code #include <bits/stdc++.h> using namespace std; string str; int calc(string s, int j) { int res = 0; for(int i = j + 1; i < s.size(); i++) { if(s[i] == s[i - 1]) res++; } return res; } int main() { cin >> str; int pos = 0; while(pos < str.size() && str[pos] == '?') pos++; for(int i = pos + 1; i < str.size(); i++) { if(str[i] == '?') { if(str[i - 1] == 'A') str[i] = 'B'; else str[i] = 'A'; } } cout << calc(str, pos) << endl; return 0; } 庆祝61 分析 枚举排列来计算肯定是不可行的。。 考虑我们已经将身高升序排序了,然后对于前k个小朋友组成队形的身高差的最大值的最小值为f(k),并且第k个和第(k-1)个小朋友是相邻的。现在我们加入第(k+1)个小朋友,考虑到第(k + 1)个小朋友身高是大于等于前面的小朋友,插入队形之后,第(k + 1)个小朋友一定与两个小朋友相邻, 所以当我们将第(k + 1)个小朋友插入到第k个和第(k - 1)个小朋友中间可以得到f(k + 1)的下界一定是max(f(k), h[k] - k[k - 2]),我们又注意到这样插入之后第(k + 1)个和第k个小朋友还是相邻的,于是这样可以一直推广下去。考虑最初3个小朋友的时候这样也是可行的, 于是问题变成了求max(h[i] - h[i - 2])。可以写出很简洁的代码。 参考code #include <bits/stdc++.h> using namespace std; const int maxn = 20 + 5; int n; int h[maxn]; int main() { scanf("%d", &n); for(int i = 0; i < n; i++) scanf("%d", &h[i]); sort(h, h + n); int ans = 0; for(int i = 2; i < n; i++) ans = max(ans, h[i] - h[i - 2]); cout << ans << endl; } 随机的机器人 分析 考虑dp[i % 2][j][k]表示走了i步之后恰好有j个红色格子,并且此时机器人正好站在第k个红色格子上的概率。最后求一个可能的状态的带权和就是所求期望。时间复杂度O(n ^ 3) 这个题应该还有很多做法,甚至可以做到O(n^2),O(n),欢迎讨论. 参考code #include <bits/stdc++.h> using namespace std; const int maxn = 500 + 5; double dp[2][maxn][maxn]; int n ; int main() { cin >> n; double ans = 0; dp[0][1][0] = 1.0; for(int i = 1; i <= n; i++) { int cur = i % 2, old = 1 - (i % 2); for(int j = 1; j <= i + 1; j++) for(int k = 0; k < j; k++) dp[cur][j][k] = 0; for(int j = 1; j <= i; j++) for(int k = 0; k < j; k++) { if(dp[old][j][k] > 0) { int pos1 = j, pos2 = k + 1; if(pos1 == pos2) ++pos1; dp[cur][pos1][pos2] += 0.5 * dp[old][j][k]; int pos3 = j, pos4 = k - 1; if(pos4 == -1) {pos3++,pos4++;} dp[cur][pos3][pos4] += 0.5 * dp[old][j][k]; } } } for(int i = 1; i <= n + 1; i++) { for(int j = 0; j < i; j++) { ans += i * dp[n % 2][i][j]; } } printf("%.1f\n", ans); return 0; } 逃离农场 分析 考虑dp[i][k][sum]表示前i个奶牛中选取k个他们的编号和为sum的方案数,于是有: dp[i][k][sum] = dp[i - 1][k][sum] + dp[i - 1][k - 1][(sum - i + n) % n] 然后可以滚动优化或者压缩一维空间。 参考code #include <bits/stdc++.h> using namespace std; const int mod = 1e9 + 7; int n, k; int dp[55][1005]; int main() { cin >> n >> k; dp[0][0] = 1; for(int i = 0; i < n; i++) { for(int j = k; j >= 1; j--) { for(int x = 0; x < n; x++) { dp[j][x] = (dp[j][x] + dp[j - 1][x - i < 0 ? x - i + n : x - i]) % mod; } } } cout << dp[k][0] << endl; return 0; }
分享
3
原味笔面经
付付
四川外国语大学·2022届

许愿猿辅导oc!!!

8.22猿辅导三面结束,秋招投递的第一家公司,也是第一个走完流程的,许愿个oc!!!也希望大家秋招能找到心仪的offer,保持好心态,冲冲冲🐛!
分享
2
超好运许愿池
小凡凡
首都经济贸易大学·2022届

苏宁2021海外留学生招聘

招聘对象:2021届海外毕业生 (2020.8-2021.8取得学位的中国籍学生) 其他时间段也可进行投递,表现优异可破格录取 详情点击下方图片查看👇 网申地址和内推请查看评论区
分享
4
校招情报局
Keddy减肥了吗
北京交通大学·2022届

华为硬件工程师笔试题型

45选择题,单选题40道,多选题5道
分享
6
先马后看

超级简历 APP

从简历直达offer,快人一步拿高薪

最新内推
35 名用户可以帮你内推
16 名用户可以帮你内推
13 名用户可以帮你内推
10 名用户可以帮你内推
9 名用户可以帮你内推
推荐投递
高途课堂
科锐福克斯
国商信息
国商信息
国商信息
国商信息
国商信息
国商信息
北京科美划一科技有限公司