当前位置:网站首页>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;
}
边栏推荐
- 【pytorch记录】pytorch的分布式 torch.distributed.launch 命令在做什么呢
- TypeError The view function did not return a valid response. The function either returned None 的解决
- 数组every和some方法的区别?
- UE4插件软链接(关联)
- Which strings will be parsed as null by FastJson?
- 【MySQL功法】第5话 · SQL单表查询
- 0730~Mysql优化
- @RequestBody和@RequestParam区别
- 【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(下) -- 搜索历史
- Vulkan与OpenGL对比——Vulkan的全新渲染架构
猜你喜欢
![[MySQL exercises] Chapter 5 · SQL single table query](/img/11/66b4908ed8f253d599942f35bde96a.png)
[MySQL exercises] Chapter 5 · SQL single table query

剑指offer-解决面试题的思路

服务器上解压文件时提示“gzip: stdin: not in gzip format,tar: Child returned status 1,tar: Error is not recovera“

The torch distributed training

SSM integration case study (detailed)

SSM框架简单介绍

sqlmap使用教程大全命令大全(图文)

【Unity】编辑器扩展-04-拓展Scene视图

【小程序项目开发-- 京东商城】uni-app之自定义搜索组件(下) -- 搜索历史
![[MySQL exercises] Chapter 4 · Explore operators in MySQL with kiko](/img/11/66b4908ed8f253d599942f35bde96a.png)
[MySQL exercises] Chapter 4 · Explore operators in MySQL with kiko
随机推荐
MySQL 高级(进阶) SQL 语句 (一)
SSM framework explanation (the most detailed article in history)
How on one machine (Windows) to install two MYSQL database
ecshop安装的时候提示不支持JPEG格式
2022 Hangzhou Electric Cup Super League 3
多版本node的安装与切换详细操作
[MySQL exercises] Chapter 2 Basic operations of databases and data tables
SSM框架简单介绍
深度理解递归,手撕经典递归问题(汉诺塔,青蛙跳台阶),保姆级教学。
UE4插件软链接(关联)
JSP page对象简介说明
关于Error EPERM operation not permitted, mkdir...几种解决办法的比较
免安装版的Mysql安装与配置——详细教程
普通函数的参数校验
【Unity】编辑器扩展-04-拓展Scene视图
Modular specifications
MySQL 数据库基础知识(系统化一篇入门)
[MySQL exercises] Chapter 5 · SQL single table query
How to restore data using mysql binlog
安装gnome-screenshot截图工具