python中线程安全的数据结构_Scala(八)-①-数据结构-集合操作-线程安全的集合-操作符重载...

① 集合操作

Why

为什么需要集合操作?集合操作都包括哪些?Scala的集合操作主要为了适应大数据的发展,我们以Map为例.于事需入局,于程需入题,先看下题.

入题

请将list(3,5,7) 中的所有元素都 * 2,将其结果放到一个新的集合中返回,即返回一个新的list(6,10,14), 请编写程序实现.

传统解决方案

object InQuestion {

def main(args: Array[String]): Unit = {

val list1 = List(3, 5, 7)

var list2 = List[Int]()

for (item

list2 = list2 :+ item * 2

}

println(list2)

}

}

优点:

处理直接

缺点:

不够简洁

没有提现出函数式编程

不利于复杂的数据处理业务

map映射操作解决方案

分析

其实就是一个关于集合元素映射操作的问题

在Scala中可以通过map映射操作来解决:将集合中的每一个元素通过指定功能(函数)映射(转换)成新的结果集合.这里其实就是所谓的将函数作为参数传递给另外一个函数,这是函数式编程的特点.

HashMap的API为例

def map[B](f: (A) ⇒ B): HashSet[B]

[B]是泛型

map是一个高阶函数,可以接收函数f:(A)=>B

HashSet[B]就是返回的新的集合

代码

将函数作为变量进行传递,其会在map函数内部再对f1进行调用,一般都会对每一个元素调用一次.

def testCaseForMap(): Unit = {

println("=============map=============")

val list1 = List(3, 5, 7)

def f1(n1: Int): Int = {

2 * n1

}

val list2 = list1.map(f1)

println(list2)

}

How

相关的函数

语法和规则

扁平化映射-flatmap函数

flat即压扁,压平,扁平化,效果就是将集合中的每个元素的子元素映射到某个函数并返回新的集合.

object CollectionOpDemo01ForFlatMap {

def main(args: Array[String]): Unit = {

val names = List("Alice", "Bob", "Nick")

def upper( s : String ) : String = {

s. toUpperCase

}

println(names.flatMap(upper))

}

}

过滤-filter函数

将符合要求的数据(筛选)放置到新的集合中

object CollectionOpDemo02FoFilter {

def main(args: Array[String]): Unit = {

val names = List("Alice", "Bob", "Nick")

def startA(s:String): Boolean = {

s.startsWith("A")

}

val names2 = names.filter(startA)

println("names=" + names2)

}

}

化简(聚合)-reducerLeft

对集合依据函数进行聚合运算,reducerLeft中的函数式二元函数.

object CollectionOpDemo03ForReducerLeft {

def main(args: Array[String]): Unit = {

val list = List(1, 20, 30, 4, 5)

def sum(n1: Int, n2: Int): Int = {

n1 + n2

}

val res = list.reduceLeft(sum)

println("res=" + res)

}

}

练习

使用化简的方法求出 List(3,4,2,7,5) 最小的值

def testCaseForWork01(): Unit = {

val list = List(1, 2, 3, 4 ,5)

def minus( num1 : Int, num2 : Int ): Int = {

num1 - num2

}

println(list.reduceLeft(minus)) // 输出? -13 // ((((1-2)-3)-4)-5) = 1-(2+3+4+5)

println(list.reduceRight(minus)) //输出? 3 // (1-(2-(3-(4-5)))) =

}

def testCaseForWork02(): Unit = {

var l = List(3,4,2,7,5)

def max(num1: Int,num2: Int):Int = {

if (num1 > num2) num1 else num2

}

def min(num1: Int,num2: Int):Int = {

if (num1 < num2) num1 else num2

}

println(l.reduceLeft(max))

println(l.reduceLeft(min))

}

折叠-fold

fold函数将上一步返回的值作为函数的第一个参数继续传递参与运算,直到list中的所有元素被遍历.

可以把reduceLeft看做简化版的foldLeft.

override /*TraversableLike*/

def reduceLeft[B >: A](f: (B, A) => B): B =

if (isEmpty) throw new UnsupportedOperationException("empty.reduceLeft")

else tail.foldLeft[B](head)(f)

代码

object CollectionOpDemo04ForFold {

def main(args: Array[String]): Unit = {

// 折叠

val list = List(1, 2, 3, 4)

def minus( num1 : Int, num2 : Int ): Int = {

num1 - num2

}

println(list.foldLeft(5)(minus)) // 相当于list(5, 1, 2, 3, 4) list.reduceLeft(minus)

println(list.foldRight(5)(minus)) // 相当于list(1, 2, 3, 4, 5) list.reduceLeft(minus)

}

}

foldLeft和foldRight 缩写方法分别是:/:和:\

def testCaseForWork01(): Unit = {

println("testCaseForWork01")

val list4 = List(1, 9, 2, 8)

def minus(num1: Int, num2: Int): Int = {

num1 - num2

}

var i6 = (1 /: list4) (minus) // ==> list4.foldLeft(0)(minus) 1-20

println(i6)

i6 = (100 /: list4) (minus) // 100 - 20

println(i6)

i6 = (list4 :\ 10) (minus) // list4.foldRight(10)(minus) // -4

println(i6)

}

扫描-scanLeft-scanRight

扫描,即对某个集合的所有元素做fold操作,但是会把产生的所有中间结果放置于一个集合中保存并返回

object CollectionOpDemo05ForScan {

def main(args: Array[String]): Unit = {

def minus( num1 : Int, num2 : Int ) : Int = {

num1 - num2

}

// scanLeft 计算每次折叠结果,第一次直接保存

//5 (1,2,3,4,5) =>(5,4,2,-1,-5,-10)

val i8 = (1 to 5).scanLeft(5)(minus) //IndexedSeq[Int]

println(i8)

def add( num1 : Int, num2 : Int ) : Int = {

num1 + num2

}

//5 (1,2,3,4,5) =>(5,6,8, 11,15,20)

// (1,2,3,4,5),5 => (20,19,17,14,10,5)

val i9 = (1 to 5).scanRight(5)(add) //IndexedSeq[Int]

println(i9)

}

}

拉链-zip

当我们需要将两个集合进行 对偶元组合并,可以使用拉链

image.png

val list1 = List(1, 2 ,3)

val list2 = List(4, 5, 6)

val list3 = list1.zip(list2)

println("list3=" + list3)

拉链的本质就是两个集合的合并操作,合并后每个元素是一个 对偶元组

集合不限于List, 也可以是其它集合比如 Array

迭代器

所有的集合都有迭代器,可以用迭代器来进行遍历.

使用迭代器遍历

object CollectionOpDemo06ForIterator{

def main(args: Array[String]): Unit = {

val iterator = List(1, 2, 3, 4, 5).iterator //

println("--------遍历方式1 -----------------")

while (iterator.hasNext) {

println(iterator.next())

}

println("--------遍历方式2 for -----------------")

for(enum

println(enum) //

}

}

}

原理

iterator的构建实际是AbstractIterator的一个匿名子类,该子类提供了hasNext next等方法

override /*IterableLike*/

def iterator: Iterator[A] = new AbstractIterator[A] {

var these = self

def hasNext: Boolean = !these.isEmpty

def next(): A =

if (hasNext) {

val result = these.head; these = these.tail; result

} else Iterator.empty.next()

流-stream

一句话:流是一个集合,用于存放无穷多个元素.末尾元素遵守lazy规则,即要使用才会进行计算.

使用tail会自动计算生成新的数据

使用head获取头元素

不能使用last,会导致程序无限循环

object CollectionOpDemo07ForStream {

def testCaseForStream01(): Unit = {

//创建Stream

def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1)

def multi(x:BigInt) : BigInt = {

x * x

}

println(numsForm(5).map(multi)) //?

}

def testCaseForQuicklyStart() = {

//创建Stream

def numsForm(n: BigInt) : Stream[BigInt] = n #:: numsForm(n + 1)

val stream1 = numsForm(1)

println(stream1) //

//取出第一个元素

println("head=" + stream1.head) //

println(stream1.tail) //

println(stream1) //?

}

def main(args: Array[String]): Unit = {

testCaseForQuicklyStart()

testCaseForStream01()

}

}

视图-view

对其他集合应用view方法来得到类似Stream的懒加载特性效果.这在python中叫做generator.

view主要用在当要生成大量数据的时候,如果一次性生成会占用大量内存.

object CollectionOpDemo08ForView {

def main(args: Array[String]): Unit = {

def eq(i: Int): Boolean = {

i.toString.equals(i.toString.reverse)

}

//1.没有使用view

val viewSquares1 = (1 to 100).filter(eq)

println(viewSquares1)

// 2.使用view来迭代生成大量数据

val viewSquares2 = (1 to 100)

.view

.filter(eq)

for (item

println(item)

}

println(viewSquares2)

}

}

② 线程安全的集合

所有线程安全的集合都是以Synchronized开头的集合

SynchronizedBuffer

SynchronizedMap

SynchronizedPriorityQueue

SynchronizedQueue

SynchronizedSet

SynchronizedStack

Why

Scala提供了针对可变集合的线程安全集合.

Scala为了充分使用多核CPU,提供了并行集合(有别于前面的串行集合),用于多核环境的并行计算

How

parallel并行DEMO

打印1~5

代码

val maxNumber = 1000000

// 单核心,输出有序

var startTime = System.currentTimeMillis()

(1 to maxNumber).foreach(println(_))

var endTime = System.currentTimeMillis()

val t1 = (endTime-startTime)/1000

println(s"单核计算花费了${t1}秒")

println()

// 多核计算,输出无序

startTime = System.currentTimeMillis()

(1 to maxNumber).par.foreach(println(_))

endTime = System.currentTimeMillis()

val t2 = (endTime-startTime)/100

println(s"单核计算花费了${t2}秒,快了${t2/t1}倍")

输出

查看并行集合中元素访问的线程

val result1 = (0 to 100).map{case _ => Thread.currentThread.getName}

val result2 = (0 to 100).par.map{case _ => Thread.currentThread.getName}

println(result1)

println(result2)

What

Divide and conquer分治算法

Scala通过splitters,combiners等抽象层来实现,主要原理是将计算工作分解很多任务,分发给一些处理器去完成,并将它们处理结果合并返回

Work stealin算法

主要用于任务调度负载均衡(load-balancing),通俗点完成自己的所有任务之后,发现其他人还有活没干完,主动(或被安排)帮他人一起干,å这样达到尽早干完的目的

③ 操作符重载

Scala中重载了大量操作符,并且准许程序员自定义重载操作符.

Why

方便使用操作符对进行计算

How

一元操作符-后置操作符: AOp 等同于 A.操作符, 如果操作符定义的时候不带()则调用时不能加括号

一元操作符-前置操作符: +、-、!、~等操作符A等同于A.unary_操作符

二元操作符~中置操作符: A Op B 等同于 A.op(B)

二元操作符-赋值操作符:A op= B 等同于 A = A op B. 比如 A += B 等价 A = A + B

object CollectionOpDemo10ForOpOverload{

def main(args: Array[String]): Unit = {

val money = new Money(100)

money + 1

money += 1

money++;

!money

println(money.money)

}

}

class Money(n : Int) {

var money : Int = n

// 二元-中置操作符

def +(n: Int):Money = {

this.money += n

this

}

// 二元赋值操作符

def +=(n: Int):Money = {

this.money += n

this

}

// 一元操作符 ++

def ++():Money = {

this.money += 1

this

}

// 一元操作符 !

def unary_!():Money = {

this.money = -this.money

this

}

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值