示例代码(含测试)在这里

需求

在甘特图的场景下,我们经常会遇到这种情况,五位员工A, B, C, D, E,可能他们的工作都是并行的,我们需要计算

某段时间内他们总的工作时长。

我们不能简单得把五个人的工作时间都加起来,因为当中会有重叠的部分。

所以这时候我们就需要一个计算时间交并集的工具。

思路

将一组离散的时间段按照开始时间,从小到大排序。像这样

[{2 7} {4 11} {10 19} {10 30} {16 18} {19 29} {23 35} {24 42} {25 30} {27 49}]

我这里将时间用十分小的秒来代替,方便理解。

循环排序后的数组,如果下一个时间段开始时间介于上个时间段的开始时间和结束时间之间,那么就进行合并,否则就分离。

可以看到我们这里有两个关键动作,合并,分离,而这个就是我们要实现的核心代码。

实现

一段连续的工作时间都会有两个点,开始时间和结束时间。

所以我们可以把这个时间结构设计成:

type T struct {

Start int64

End int64

}

而一个人的工作时间是由多个 T 组成的,所以我们在定义一个切片类型

type TSlice []T

为了能顺序合并时间,我们需要将TSlice进行排序。

我们知道 Go 中有个 sort 包,我们只需要实现 sort 类型的接口,就能实现 TSlice 的排序了。

我们实现下:

func (t TSlice) Len() int { return len(t) }

func (t TSlice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }

func (t TSlice) Less(i, j int) bool { return t[i].Start < t[j].Start }

三个方法分别是,长度、交换位置、比小。

这样一来,我们就能直接用 sort.Stable() 稳定排序,对我们的时间段切片排序了。

好,接下来我们实现并集的方法,我们取名为 Union:

func (t TSlice) Union() TSlice {

// 新建一个空的时间切片

var s TSlice

// 如果有至少两个是时间段,我们才排序,否则直接返回

if len(t) > 1 {

// @todo 合并逻辑

}

return s

}

Union 方法将会返回一个同样的 TSlice 时间切片,只不过是经过并集处理的。

一旦 t 中的时间段个数大于1,我们就要执行处理逻辑了:

if len(t) > 1 {

sort.Stable(t)

s = append(s, t[0])

// @todo 循环比较合并

}

我们先对时间切片进行排序,然后把第一个时间段作为第一个元素放进我们的结果 TSlice 中,好让我们开始进行循坏的比较。

if len(t) > 1 {

sort.Stable(t)

s = append(s, t[0])

for k, v := range t {

// 如果开始时间大于结束时间,那其实是错误数据,但是我们这里正常返回

// 你可以根据自己的需要定制错误处理逻辑

if v.Start > v.End {

return s

}

// 第一组元素我们不做任何操作

if k == 0 {

continue

}

// 当开始时间介于上一个时间段的开始时间和结束时间之间

if v.Start >= s[len(s)-1].Start && v.Start <= s[len(s)-1].End {

// 合并

if v.End > s[len(s)-1].End {

s[len(s)-1].End = v.End

}

// 如果大于上一个时间段的结束时间

} else if v.Start > s[len(s)-1].End {

// 分离

inner := T{Start: v.Start, End: v.End}

s = append(s, inner)

}

}

}

来张图其实就清楚了:

可以看到最后输出的也是一个 TSlice 类型。

上面就是 union,求并集的过程,那交集的?

其实交集也很简单,如果两个时间段相交,我们只要判断:开始时间取最大的那个,结束时间取两个时间段中最小的那个。

func (t TSlice) Intersect() TSlice {

var s TSlice

if len(t) > 1 {

sort.Stable(t)

s = append(s, t[0])

for k, v := range t {

if v.Start > v.End {

return s

}

if k == 0 {

continue

}

// 两个时间段相交

if v.Start >= s[0].Start && v.Start <= s[0].End {

// 开始时间取最大的那个

s[0].Start = v.Start

// 结束时间取最小的那个

if v.End <= s[0].End {

s[0].End = v.End

}

} else {

return s[:0]

}

}

}

return s

}

一样,我们来个图:

需要注意的是,这个求交集的结果是全相交--只有当所有时间段都有共同时间才会有结果。

这样的需求在实际过程中用到的是不是不太多??所以我想是不是能够实现:一次相交,两次相交...的条件筛选。

看看效果

我们随机生成了一组时间切片

func makeTimes(t int) TSlice {

var set TSlice

rand.Seed(time.Now().Unix())

for i := 0; i < t; i++ {

randStart := rand.Int63n(50)

randEnd := randStart + rand.Int63n(25) + 1

set = append(set, T{Start: randStart, End: randEnd})

}

return set

}

testSet := makeTimes(10) // 生成10个时间段的时间切片

res := testSet.Union() // 直接调用 Union() 或者 Intersect()

输入数据为:

[{10 21} {34 52} {49 54} {18 31} {26 44} {24 27} {43 51} {41 53} {20 41} {48 67}]

输出结果:

[{10 67}]

结果还行~

额外

我发现在求并集的过程中,会要求求最终的时间之和,所以我们为 TSlice 加一个 Sum() 方法,

就是简单的循环求和:

func (t TSlice) Sum() (sum int64) {

for i := 0; i < len(t); i++ {

sum += t[i].End - t[i].Start

}

return sum

}

有疑问加站长微信联系(非本文作者)

多个时间合并并集mysql_写个 Go 时间交并集小工具相关推荐

  1. 用python3+ PyQt5写一个NFC模块的串口小工具的一星期

    用python3+ PyQt5写一个NFC模块的串口小工具的一星期 原因始于我们的小团队,没有写Windows上位机的人才.自己的[NFC读读写模](https://shop165836966.tao ...

  2. 写了个MySQL数据备份小工具,放出来跟大家分享一下,欢迎拍砖。

    自己写了个MySQL数据备份小工具,放出来跟大家分享一下,欢迎拍砖. 因为数据库中有blob类型的字段,用SQLyog等工具备份出的脚本都是乱码,没办法导入,可是又经常要备份MySQL数据库,以前一直 ...

  3. switchyomega规则列表备份_求人不如求己,自己动手写一个CSDN博客备份小工具?...

    前提概要 背景 因为笔者在上个月的时候,突然想扩展一下技术栈,不能仅仅局限于Java,还是得掌握一门工具语言,不然显得太low.所以也就对Python和Golang类的语言有了一些兴趣.也就在上个月简 ...

  4. 写了一个测试正则表达式的小工具

    这两天写了两个蜘蛛程序用来自动下载漫画,许多时候都是用他在网页中通过正则表达式获取关键字和信息.我用的正则表达式的工具是Expresso,这个工具无疑是目前最好的正则表达式的工具之一.但用着用着就觉得 ...

  5. 写了两个简单的小工具,文件夹文件操作的

    一,文件夹A下的文件夹下的文件,移到文件夹A下. 二,经常上贴吧什么的,有些图贴,会直接网页全部保存为,结果是一个html文件,和引用资源的文件夹,文件夹下有很多无用的文件,写了个方法,把图片另存为, ...

  6. 写一个简单的准星辅助小工具

    由于平时喜欢玩射击游戏,人又很菜,于是突发奇想做个显示准星一直显示在屏幕中间的小程序. 思路:创建透明窗口,在窗口中间画准星.允许点击窗口后面的内容 准星窗口: 1.设置窗口属性,画出中间准星 < ...

  7. 关于写毕业设计论文的一些实用小工具收藏

    1.英文文献查找 1>谷歌学术镜像:谷歌学术镜像_Google镜像站 2>中国知网(用校园网):中国知网 3>百度学术:百度学术 - 保持学习的态度 4>日光图书馆(付费的): ...

  8. python批量裁剪图片_用Python写了一个图片格式批量处理工具

    来源:blog.csdn.net/kimol_justdo 前言 就在昨天,正当我在刺激战场厮杀时,"叮叮叮",微信来消息了.我心想:"这是肾马情况?" 我打开 ...

  9. python小工具小发明_用python写PDF转换器的实现

    前言 某个夜深人静的夜晚,夜微凉风微扬,月光照进我的书房~ 当我打开文件夹以回顾往事之余,惊现许多看似杂乱的无聊代码.我拍腿正坐,一个想法油然而生:"生活已然很无聊,不如再无聊些叭" ...

  10. 时隔这么长时间,又回来写博客了

    时隔这么长时间,又回来写博客了 想想距离上次写博客大概有一年的时间了吧,其实这一年并没有闲着,而是我20年来最忙碌的一年了.假期的实习.旅游.还有学校的项目.但是欣慰的是这一年也是收获最多的一年.现在 ...

最新文章

  1. 微软发布WP SDK8.0 新增语音、应用内支付等原生API
  2. 企业USB权限控制心得
  3. AT89C52编程开发源代码
  4. python网络爬虫入门小程序_Python 实现网络爬虫小程序
  5. 离散对数(关于方程x^A=B(mod C)的解)
  6. 新建Acquisition contract出错的问题
  7. new 实例化对象是啥意思_二. 初步认识JS中的类和对象
  8. php 清除指定session,PHP如何操作指定的session?
  9. PHP使用MySQL数据库
  10. 微信服务号开发整体流程
  11. 竹子买车商学院,知名汽车人钟志,销售实战培训
  12. Autojs 3.0文档学习之设备信息
  13. 经纬度计算两地之间的距离(原理与方法)
  14. html图片滤色,CSS3图片混合(Blend)效果详解
  15. MATLAB | 那些你不得不知道的MATLAB小技巧(四)
  16. 为什么有时优盘是只读模式_如何设置U盘为只读模式
  17. 《文化相对论》圆满收官!思想交锋,文明互鉴!
  18. yDAI受创 Curve“喜”收意外之财
  19. Java实现第八届蓝桥杯拉马车
  20. 学前教育专业计算机实训室,【学前教育专业实训室建设方案】

热门文章

  1. netlogon启动后停止_优雅停止 SpringBoot 服务,拒绝 kill 9 暴力停止!
  2. Matlab信号提取、频谱分析、滤波、阈值设定、寻找极值点
  3. 利用PCA降维的手工计算实例
  4. 在Windows下搭建RocketMQ
  5. [转]【基于zxing的编解码实战】精简Barcode Scanner篇
  6. Python中os.listdir和os.walk的区别
  7. c语言A 100 开头地址,C语言库函数_-_A开头
  8. springboot前台页面写Java代码,接收后台数据,SpringBoot整合Thymeleaf的使用,实现非ajax请求后台的数据实现和遍历效果,以及数据的页面展示
  9. lavavel php 手册,Laravel文档工具
  10. python求偏度系数_python pandas库和stats库计算偏度和峰度(附程序)