当前位置:网站首页>Scala基础【seq、set、map、元组、WordCount、队列、并行】
Scala基础【seq、set、map、元组、WordCount、队列、并行】
2022-07-31 08:55:00 【hike76】
文章目录
一 seq集合
LIst集合特性:数据有序(插入有序),可以存放重复数据
val list = List(1,3,4,2,1)
1 不可变List
一般会采用List
val seq = Seq(1,2,3,4) //List(1, 2, 3, 4)
val list = List(1,2,3,4) //List(1, 2, 3, 4)
在list首尾添加数据
val ints: List[Int] = list :+ 5 // List(1, 2, 3, 4, 5)
val ints1: List[Int] = 5 +: list // List(5, 1, 2, 3, 4)
Nil 在集合中表示空集合,主要作用是向里面存放数据
println(ints2) //List()
val ints2 = 1 :: 2 :: 3 :: Nil //List(1, 2, 3)
把一个集合添加到另一个集合中
:: 当成整体 :::当成个体
val ints3 = 1 :: 2 :: 3 :: list :: Nil //List(1, 2, 3, List(1, 2, 3, 4))
val ints4 = 1 :: 2 :: 3 :: list ::: Nil //List(1, 2, 3, 1, 2, 3, 4)
2 可变list
val list = ListBuffer(1,2,3,4)
val unit = list.update(0,5) //改变自身,不会产生新集合
println(list) //ListBuffer(5, 2, 3, 4)
val ints = list.updated(0,6) //会产生新集合,以前的集合不变
println(list) //ListBuffer(5, 2, 3, 4)
其他的操作与数组相同
相互转化
val list1: Seq[Int] = list.toList
val buffer: mutable.Seq[Int] = list1.toBuffer
二 set集合
set集合特性:数据无序,不可重复
val set = Set(1,2,3,4,1,2,3,4)
1 不可变set
常用操作同List,Array
val set = Set(1,2,3,4,1,2,3,4)
2 可变set
val set = mutable.Set(1,2,3,4)
set没有append、insert方法,因为它没有最后一个元素,没有位置的概念
update方法用于更新set集合
val set = mutable.Set(1,2,3,4)
set.add(5)
println(set) //Set(1, 5, 2, 3, 4)
set.update(5,true)
println(set) //Set(1, 5, 2, 3, 4)
set.update(5,false)
println(set) //Set(1, 2, 3, 4)
set.update(6,true)
println(set) //Set(1, 2, 6, 3, 4)
set.remove(6)
println(set) //Set(1, 2, 3, 4)
常用操作同List,Array
三 Map集合
Map集合特性:数据无序,k不能重复,v可以重复。当k相同的时候,v会被覆盖
map以k-v键值对的方式存储数据
scala中的k-v键值对十分特殊
1 不可变Map
默认情况下为不可变Map
val map = Map(
"a" -> 1,"b" -> 1,"c" -> 1,"d" -> 1
)
println(map)
其他方法同
2 可变Map
val map = mutable.Map(
"a" -> 1,"b" -> 1,"c" -> 1,"d" -> 1
)
map.put("e",2)
println(map) //Map(e -> 2, b -> 1, d -> 1, a -> 1, c -> 1)
map.update("a",11)
println(map) //Map(e -> 2, b -> 1, d -> 1, a -> 11, c -> 1)
map.remove("c")
println(map) //Map(e -> 2, b -> 1, d -> 1, a -> 11)
java从HashMap中获取一个不存在的key,会返回null,因为HashMap允许存放空键空值
空指针问题
scala为了解决空指针问题专门设计了Option类型
Option:选项,只有两个对象,Some和None
val map = mutable.Map(
"a" -> 1,"b" -> 1,"c" -> 1,"d" -> 1
)
val maybeInt: Option[Int] = map.get("a")
val maybeInt1: Option[Int] = map.get("aaa")
当Some调用get方法会返回值,当None调用get会返回NoSuchElementException异常
if( maybeInt.isEmpty){
println("没有对应key的值")
}else{
println("对应key的值为" + maybeInt.get) //对应key的值为1
}
if( maybeInt1.isEmpty){
println("没有对应key的值" + maybeInt1.get) //NoSuchElementException
}else{
println("对应key的值为" + maybeInt1.get)
}
当取不到值的时候给一个默认值
if( maybeInt1.isEmpty){
println("没有对应key的值,提供的默认值为:" + maybeInt1.getOrElse(0))
//没有对应key的值,提供的默认值为:0
}else{
println("对应key的值为" + maybeInt1.get)
}
避免使用判断
println(maybeInt.getOrElse(0)) //1
println(maybeInt1.getOrElse(0)) //0
简化
println(maybeInt.getOrElse(0)) //1
println(maybeInt1.getOrElse(0)) //0
四 元组Tuple
scala可以将无关的元素组合在一起形成一个整体进行访问,这个整体结构称之为元组的组合,简称元组
-Tuple
因为元组中的数据没有关系,所以只能通过顺序号进行访问
Tuple是一个集合对象,也有对应的类型(Int,String,Int)
val t : (Int,String,Int) = (1,"张三",20)
println(t._1)
println(t._2)
println(t._3)
println(t)
scala中元组也有对应的类型(不常用)
val t1 :Tuple3[Int,String,Int] = (1,"zhangsan",20)
Tuple类型最多存放元素的数量为22个,但是类型没有约束,也可以存放Tuple,List,Map等。
1 对偶元组
如果元组中的元素只有两个,称之为对偶元组,也可以叫做键值对
val kv = (1,"zhangsan")
//val tuple = 1 -> "zhangsan"
因此map可以这样定义
val map = Map(
("a",1),("b",2),("c",1)
)
println(map) //Map(a -> 1, b -> 2, c -> 1)
遍历map
// a=1
// b=2
// c=1
map.foreach(
t => {
println(t._1 + "=" + t._2)
}
)
将map转换为有序的list
val list: Seq[(String, Int)] = map.toList
改写wordcount第四步
val wordCount: Map[String, Int] = wordGroup.map(
kv => {
val k = kv._1
val v = kv._2
(k,v.size)
}
)
五 WordCount
1 wordcount扩展
修改原文件中内容样式为(“hello scala”,4),表示hello scala字符串出现4次
思路一:将(“hello scala”,4)转换成(“hello scala hello scala hello scala hello scala”),再进行处理
def main(args: Array[String]): Unit = {
val list = List(
("hello scala",4),
("hello word",2)
)
val list1 = list.map(
t => {
val line = t._1
val cnt = t._2
(line + " ") * cnt
}
)
println(list1)
}
思路二:将(“hello scala”,4)转换成(“hello”,4),(“scala”,4),再进行相同单词相加
val list2 = list.flatMap(
t => {
val line = t._1
val cnt = t._2
val dates = line.split(" ")
dates.map(
word => {
(word, cnt)
}
)
}
)
println(list2) //List((hello,4), (scala,4), (hello,2), (word,2))
val groupData: Map[String, List[(String, Int)]] = list2.groupBy(_._1)
println(groupData)
/** * Map( * scala -> List((scala,4)), * word -> List((word,2)), * hello -> List((hello,4), (hello,2)) * ) */
val groupData1 = groupData.mapValues(
list => {
list.map(_._2).sum
}
)
println(groupData1) //Map(scala -> 4, word -> 2, hello -> 6)
2 wordcount练习
完成不同省份的商品点击排行
word(省份-商品)–count(1)
(1)准备数据
val datas = List(
("zhangsan", "河北", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "鞋"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "鞋"),
("zhangsan", "河南", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "鞋"),
("zhangsan", "河北", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "帽子"),
("zhangsan", "河南", "鞋"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "电脑"),
("zhangsan", "河南", "鞋"),
("lisi", "河南", "衣服"),
("wangwu", "河南", "电脑"),
("zhangsan", "河南", "电脑"),
("lisi", "河北", "衣服"),
("wangwu", "河北", "帽子")
)
(2)将原始数据进行结构转换
(人,省份,商品)=>(省份-商品,1)
val mapDatas = datas.map(
t => {
(t._2 + "-" + t._3, 1)
}
)
/** * List( * (河北-鞋,1), (河北-衣服,1), (河北-鞋,1), * (河南-鞋,1), (河南-衣服,1), (河南-鞋,1), * (河南-鞋,1), (河北-衣服,1), (河北-鞋,1), * (河北-鞋,1), (河北-衣服,1), (河北-帽子,1), * (河南-鞋,1), (河南-衣服,1), (河南-帽子,1), * (河南-鞋,1), (河北-衣服,1), (河北-帽子,1), * (河北-衣服,1), (河北-电脑,1), (河南-鞋,1), * (河南-衣服,1), (河南-电脑,1), (河南-电脑,1), * (河北-衣服,1), (河北-帽子,1)) */
(3)将转换结构后的数据进行分组
val groupDatas: Map[String, List[(String, Int)]] = mapDatas.groupBy(_._1)
/** * Map( * 河南-衣服 -> List((河南-衣服,1), (河南-衣服,1), (河南-衣服,1)), * 河北-衣服 -> List((河北-衣服,1), (河北-衣服,1), (河北-衣服,1), (河北-衣服,1), (河北-衣服,1), (河北-衣服,1)), * 河南-帽子 -> List((河南-帽子,1)), * 河北-鞋 -> List((河北-鞋,1), (河北-鞋,1), (河北-鞋,1), (河北-鞋,1)), * 河南-电脑 -> List((河南-电脑,1), (河南-电脑,1)), * 河南-鞋 -> List((河南-鞋,1), (河南-鞋,1), (河南-鞋,1), (河南-鞋,1), (河南-鞋,1), (河南-鞋,1)), * 河北-电脑 -> List((河北-电脑,1)), * 河北-帽子 -> List((河北-帽子,1), (河北-帽子,1), (河北-帽子,1))) */
(4)将分组后的数据进行统计聚合
val cntDatas: Map[String, Int] = groupDatas.mapValues(
list => list.size
)
println(cntDatas)
/** * Map( * 河南-衣服 -> 3, * 河北-衣服 -> 6, * 河南-帽子 -> 1, * 河北-鞋 -> 4, * 河南-电脑 -> 2, * 河南-鞋 -> 6, * 河北-电脑 -> 1, * 河北-帽子 -> 3) */
(5)将聚合的结果进行结构转换
将相同省份的数据准备放在一起
(省份-商品,count)=>(省份,(商品,count))
val mapDatas1 = cntDatas.map(
kv => {
val k = kv._1
val cnt = kv._2
val ks = k.split("-")
(ks(0), (ks(1), cnt))
}
)
println(mapDatas1)
/** * Map(河南 -> (鞋,6), 河北 -> (帽子,3)) */
改变了K的结构,K相同,会进行覆盖,所以不能使用map集合
val mapDatas1 = cntDatas.toList.map(
kv => {
val k = kv._1
val cnt = kv._2
val ks = k.split("-")
(ks(0), (ks(1), cnt))
}
)
/** * List( * (河南,(衣服,3)), * (河北,(衣服,6)), * (河南,(帽子,1)), * (河北,(鞋,4)), * (河南,(电脑,2)), * (河南,(鞋,6)), * (河北,(电脑,1)), * (河北,(帽子,3)) * ) */
(6)将转换后的结果按照省份进行分组
val groupDatas1 = mapDatas.groupBy(_._1)
/** * Map( * 河南 -> * List((河南,(衣服,3)), (河南,(帽子,1)), (河南,(电脑,2)), (河南,(鞋,6))), * 河北 -> * List((河北,(衣服,6)), (河北,(鞋,4)), (河北,(电脑,1)), (河北,(帽子,3)))) */
val groupDatas1 = mapDatas1.groupBy(_._1).mapValues(
list => list.map(_._2)
)
println(groupDatas1)
//Map(
// 河南 -> List((衣服,3), (帽子,1), (电脑,2), (鞋,6)),
// 河北 -> List((衣服,6), (鞋,4), (电脑,1), (帽子,3))
// )
(7)将转换结构后的数据进行排序
val groupDatas1 = mapDatas1.groupBy(_._1).mapValues(
list => list.map(_._2).sortBy(_._2)(Ordering.Int.reverse)
)
取前三名
val groupDatas1 = mapDatas1.groupBy(_._1).mapValues(
list => list.map(_._2).sortBy(_._2)(Ordering.Int.reverse).take(3)
)
六 队列
Scala也提供了队列(Queue)的数据结构,队列的特点就是先进先出。进队和出队的方法分别为enqueue和dequeue。
def main(args: Array[String]): Unit = {
val que = new mutable.Queue[String]()
// 添加元素
que.enqueue("a", "b", "c")
val que1: mutable.Queue[String] = que += "d"
println(que eq que1) //true
// 获取元素
println(que.dequeue()) //a
println(que.dequeue()) //b
println(que.dequeue()) //c
}
kafka中如何保证消费数据的有序
kafka中的topic有多个分区,每一个分区可以理解为一个队列
分区内有序,分区间无序,指的是存储有序与无序
消费者是以消费者组为单位进行消息的消费
所以如何保证消费数据的有序呢
- kafka分区存储有序:所有数据都放在一个分区内,有多个分区也只能放在一个分区
- kafka生产有序:kafka在生产数据时,如果失败,会将消息放在队尾,重新发送,使用Deque,双端队列实现kafka生产有序
七 并行
以下三种概念建立在多线程的基础之上
并行:多核,一个物理核拆分成了多个虚拟核,每个线程可以抢占一个,当多个线程抢占同一个虚拟核称为并发,反之为并行,同时执行
并发:多个线程不按照顺序抢占CPU资源,当一个线程抢到之后,其他线程阻塞,也可以理解为交叉执行,一个线程执行一段时间
串行:一个线程完成之后才能轮到另一个线程执行,多个线程按照顺序抢占CPU资源
Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算
def main(args: Array[String]): Unit = {
val result1 = (0 to 100).map{
x => Thread.currentThread.getName}
val result2 = (0 to 100).par.map{
x => Thread.currentThread.getName}
println(result1) //全为main线程执行
println(result2) //多线程执行
}
线程安全问题
多线程并发执行时,对共享内存(堆)中的共享对象的属性进行修改,所导致的数据冲突问题,称为线程安全问题
方法不会出现问题,因为执行方法时会进行压栈,栈内存每个线程独享
并行是在多个核内执行,除修改第三方资源不会出现问题
以下代码输出结果为:lisi,lisi,main方法…
public class TestThreadSafe {
public static void main(String[] args) {
final User1 user1 = new User1();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
user1.name = "zhangsan";
try {
Thread.sleep(1000);
}catch (Exception e){
}
System.out.println(user1.name);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
user1.name = "lisi";
try {
Thread.sleep(1000);
}catch (Exception e){
}
System.out.println(user1.name);
}
});
t1.start();
t2.start();
System.out.println("main方法执行完毕");
}
}
class User1{
public String name;
}
多例不会出现线程安全问题,以下为多例
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
Test();
}
});
new Thread(new Runnable() {
@Override
public void run() {
Test();
}
});
}
public static void Test(){
StringBuilder builder = new StringBuilder();
for(int i = 0 ; i < 100 ; i++){
builder.append(i);
}
System.out.println(builder);
}
}
解决线程安全问题
栈上分配,在栈上面分配对象而不是在堆上面,缺点是当对象执行完毕会被弹栈回收
逃逸分析:方法返回对象,但对象被回收了,或者是对象来自于外部,方法执行完毕之后,也将对象弹栈
public User test(){
User user = new Uesr();
user.xxx;
user.yyy;
return user;
}
public void test(User user){
user.xxx;
user.yyy;
}
边栏推荐
- Linux安装mysql
- 基于学生成绩管理系统(附源代码及数据库)
- 【小程序项目开发 -- 京东商城】uni-app 商品分类页面(下)
- mysql安装教程【安装版】
- Flutter Paystack implements all options
- 文件的逻辑结构与物理结构的对比与区别
- SQL连接表(内连接、左连接、右连接、交叉连接、全外连接)
- 【云原生】微服务之Feign的介绍与使用
- I advise those juniors and juniors who have just started working: If you want to enter a big factory, you must master these core skills!Complete Learning Route!
- Splunk Workflow action 给我们带来的好处
猜你喜欢
随机推荐
深度理解递归,手撕经典递归问题(汉诺塔,青蛙跳台阶),保姆级教学。
利用frp服务器进行内网穿透ssh访问
sqlmap使用教程大全命令大全(图文)
MySQL安装常见报错处理大全
SQL join table (inner join, left join, right join, cross join, full outer join)
ScheduledExecutorService - 定时周期执行任务
TypeError The view function did not return a valid response. The function either returned None 的解决
ONES 入选 CFS 财经峰会「2022数字化创新引领奖」
哪些字符串会被FastJson解析为null呢
第八章 、接口
Flutter Paystack implements all options
编译器R8问题Multidex
关于挂载EXfat文件格式U盘失败的问题
Hematemesis summarizes thirteen experiences to help you create more suitable MySQL indexes
MySQL安装教程
Ubuntu22.04安装mysql
02 Truffle TutorialToken 示例
MySQL 排序
普通函数的参数校验
【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(下) -- 搜索历史









