Scala 经典的模式匹配和尾递归


package io import java.io.{BufferedWriter, File, FileWriter}
import java.text.SimpleDateFormat import scala.annotation.tailrec
import scala.io.Source /**
* author: HuaZhe Ray
*
* describe: 计算服务调用平均时长
*
* createDate: 2017/12/15
* createTime: 10:57
*
*/
object AverageService { type TIME = String
type THREAD = String
type SERVICE = String
type WAYS = String
type METHOD = String
val sdf = new SimpleDateFormat("MM-dd hh:mm:ss SSS")
val regex = """(\d{2}-\d{2} \d{2}:\d{2}:\d{2} \d{3}) ([^\s]+) DEBUG ([^\s]+) ([^\s]+) ([^\s]+) ([^\s]+) (.+)""".r def main(args: Array[String]): Unit = {
// 服务调用次数
countByServiceName Thread.sleep(1000) // 服务调用时长
analyzeAverageTime
} /**
* 最新优化,求服务调用次数 根据 带有request单词的作为一次服务,并过滤掉 INFO 日志, 取 DEBUG 日志
* 2017-12-14 14:50
*/
def countByServiceName(): Unit = { val source = Source.fromFile("E:\\scala\\detail-test.log", "UTF-8") val lists:List[(String,String,String,String,String)] = source.getLines().collect{
case regex(timestamp, thread,c,service,version,method,requests) => (timestamp,thread,service,method,requests)
}.toList val requests:List[(String,String,String)] = lists.filter(_._5.contains("request")).map (line =>{
(line._1,line._2,line._3+"."+line._4)
}) val countByServiceName:Map[String,Int] = requests.map((_, 1)).groupBy(_._1._3).map(t=>(t._1,t._2.size)) countByServiceName.foreach {
case (service, count) => println(s"$service count:$count")
} } /**
* 2017-12-15 统计服务调用平均时长
*
* 思路,根据正则 截取到 request 和 response 的 服务 ,然后根据时间排序 ---> 每次调用的 response - request 得到 服务调用时长
*/
def analyzeAverageTime(): Unit = {
val source = Source.fromFile("E:\\scala\\detail-test.log", "UTF-8") val lists:List[(TIME,THREAD,SERVICE,METHOD,WAYS)] = source.getLines().collect{
case regex(timestamp, thread,c,service,version,method,requests) => (timestamp,thread,service,method,requests)
}.toList val requests:List[(TIME,THREAD,SERVICE,WAYS)] = lists.filter(_._5.contains("request")).map (line =>{
(line._1,line._2,line._3+"."+line._4,"request")
}) val response:List[(TIME,THREAD,SERVICE,WAYS)] = lists.filter(_._5.contains("response")).map (line =>{
(line._1,line._2,line._3+"."+line._4,"response")
})
// 得到所有 request 和 response 结果
val totalServices = (requests ++ response).sortWith((t1,t2) => t1._1 < t2._1).take(10) //具体进行处理
processByTailRec(totalServices,Map[(THREAD,SERVICE),TIME]())
} /**
* 通过定义 mutable Map 来 存放 foreach 临时变量, 进行相减操作
* @param array
*/
def process(array:List[(TIME,THREAD,SERVICE,WAYS)]): Unit = {
val pendings = collection.mutable.Map[(THREAD,SERVICE),TIME]() array.foreach{
case (time,thread,service,ways) => if(ways=="request") {
pendings += (thread,service) -> time
}
else { pendings.get((thread,service)) match {
case Some(time0) => val msg = s"Thread: ${thread} Service: ${service} average-time: ${BigDecimal(sdf.parse(time).getTime - sdf.parse(time0).getTime)} ms"
pendings.remove((thread, service))
writeLogToFile(msg) ; println(msg)
case None => println("nothing")
}
}
}
} /**
* 使用尾递归的方法,消除 var 和 mutable Map
* @param array
* @param pendings
*/
@tailrec
def processByTailRec(array:List[(TIME,THREAD,SERVICE,WAYS)],pendings:Map[(THREAD,SERVICE),TIME]): Unit ={ array match {
case (time,thread,service,"response") :: tail =>
pendings.get((thread, service)) match { case Some(time0) =>
val msg = s"Thread: ${thread} Service: ${service} average-time: ${BigDecimal(sdf.parse(time).getTime - sdf.parse(time0).getTime)} ms"
writeLogToFile(msg) ; println(msg) processByTailRec(tail, pendings - ((thread, service))) case None =>
processByTailRec(tail, pendings)
} case (time, thread, service, "request") :: tail =>
processByTailRec(tail, pendings + ((thread, service) -> time) ) case Nil => None
}
} /**
* 写文件
* @param args
*/
def writeLogToFile(args:String): Unit ={ val fw = new FileWriter(new File("E:\\scala\\service_average.log"),true)
//写入中文字符时会出现乱码
val bw = new BufferedWriter(fw)
bw.write(args + "\r\n")
bw.close()
fw.close()
}
}

Scala 经典的模式匹配和尾递归的更多相关文章

  1. 第74讲:从Spark源码的角度思考Scala中的模式匹配

    今天跟随王老师学习了从源码角度去分析scala中的模式匹配的功能.让我们看看源码中的这一段模式匹配: 从代码中我们可以看到,case RegisterWorker(id,workerHost,.... ...

  2. (数据科学学习手札49)Scala中的模式匹配

    一.简介 Scala中的模式匹配类似Java中的switch语句,且更加稳健,本文就将针对Scala中模式匹配的一些基本实例进行介绍: 二.Scala中的模式匹配 2.1 基本格式 Scala中模式匹 ...

  3. Scala基础:模式匹配和样例类

    模式匹配 package com.zy.scala import scala.util.Random /** * 模式匹配 */ object CaseDemo { def main(args: Ar ...

  4. scala里的模式匹配和Case Class

    模式匹配的简介 scala语言里的模式匹配可以看作是java语言中switch语句的改进. 模式匹配的类型 包括:常量模式.变量模式.构造器模式.序列模式.元组模式以及变量绑定模式等. 常量模式匹配 ...

  5. Scala面向对象和模式匹配

    我们要封装数据,定义模板等操作,所以我们需要面向对象. 一.scala中的单例对象 在scala当中,是没有static的,scala给我们提供了单例模式的实现方法.就是使用关键字object. st ...

  6. scala中的模式匹配

    基本语法 变量 match { case 值1 => 代码 case 值2 => 代码 ... case 值N if (...) => 代码 case _ => 代码 } 常量 ...

  7. [Scala] Pattern Matching(模式匹配)

    Scala中的match, 比起以往使用的switch-case有著更強大的功能, 1. 傳統方法 def toYesOrNo(choice: Int): String = choice match ...

  8. scala 学习笔记--模式匹配

    1.switch java代码 switch (cause) { case ‘2‘ : dropTime=time; case ‘8’:case ‘9’ : case ‘10’:case ‘11’ : ...

  9. 第3节 Scala中的模式匹配:1 - 5

    7.    模式匹配和样例类 Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句.类型检查等.并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配. 7.1 ...

随机推荐

  1. layui使用 ——父,子页面传值

    页面传值是非常常用的,layui自带弹窗功能,但是内置使用的是location.href 暂时没找到方法条件请求头,所以在后台需要放开拦截器, layer.open({ type : 2, title ...

  2. 06-码蚁JavaWeb之Servlet生命周期与基本配置

    学习地址:[撩课-JavaWeb系列1之基础语法-前端基础][撩课-JavaWeb系列2之XML][撩课-JavaWeb系列3之MySQL][撩课-JavaWeb系列4之JDBC][撩课-JavaWe ...

  3. 从MySQL到ORM(三):连接、存储过程和用户权限

    一.联结表 数据仍使用前文中的数据. 1.子查询 作为子查询的SELECT语句只能查询单个列.企图检索多个列将返回错误. -- 作为查询条件使用 -- 查看TNT2订单对应的客户ip(order表) ...

  4. 【SSH网上商城项目实战16】Hibernate的二级缓存处理首页的热门显示

    转自:https://blog.csdn.net/eson_15/article/details/51405911 网上商城首页都有热门商品,那么这些商品的点击率是很高的,当用户点击某个热门商品后需要 ...

  5. C#学习笔记-外观模式

    题目:股民买卖股票 实现: static void Main(string[] args) { Stock1 gu1 = new Stock1(); Stock2 gu2 = new Stock2() ...

  6. MySQL Metadata

    http://www.devart.com/dotconnect/mysql/docs/MetaData.html In this overload first parameter is name o ...

  7. java截取字符串

    public class Temp { public static void main(String[] args) { String a="dsadgafa34"; System ...

  8. arcgis 3种方法快速制作tpk文件(转)

    来自:http://blog.csdn.net/arcgis_mobile/article/details/8048549 tpk是ArcGIS10.1推出的一种新的数据文件类型,主要是用于将切片文件 ...

  9. js获取上一页、当前页及域名url

    一个业务中可能会用到,跳转到另个页面后, 又后退回之前的页面,之前的页面上有个判断提示一定会出 网上搬了下代码 console.log("js获取当前域名"+window.loca ...

  10. PID控制算法

    PID控制算法 四轴如何起飞的原理 四轴飞行器的螺旋桨与空气发生相对运动,产生了向上的升力,当升力大于四轴的重力时四轴就可以起飞了. 四轴飞行器飞行过程中如何保持水平: 我们先假设一种理想状况:四个电 ...