代码片段 - Golang 实现集合操作
------------------------------------------------------------
如果用于多例程,可以使用下面的版本:
------------------------------------------------------------ package main import (
"fmt"
"sort"
"sync"
) type Set struct {
sync.RWMutex
m map[int]bool
} // 新建集合对象
// 可以传入初始元素
func New(items ...int) *Set {
s := &Set{
m: make(map[int]bool, len(items)),
}
s.Add(items...)
return s
} // 创建副本
func (s *Set) Duplicate() *Set {
s.Lock()
defer s.Unlock()
r := &Set{
m: make(map[int]bool, len(s.m)),
}
for e := range s.m {
r.m[e] = true
}
return r
} // 添加元素
func (s *Set) Add(items ...int) {
s.Lock()
defer s.Unlock()
for _, v := range items {
s.m[v] = true
}
} // 删除元素
func (s *Set) Remove(items ...int) {
s.Lock()
defer s.Unlock()
for _, v := range items {
delete(s.m, v)
}
} // 判断元素是否存在
func (s *Set) Has(items ...int) bool {
s.RLock()
defer s.RUnlock()
for _, v := range items {
if _, ok := s.m[v]; !ok {
return false
}
}
return true
} // 统计元素个数
func (s *Set) Count() int {
s.Lock()
defer s.Unlock()
return len(s.m)
} // 清空集合
func (s *Set) Clear() {
s.Lock()
defer s.Unlock()
s.m = map[int]bool{}
} // 空集合判断
func (s *Set) Empty() bool {
s.Lock()
defer s.Unlock()
return len(s.m) == 0
} // 获取元素列表(无序)
func (s *Set) List() []int {
s.RLock()
defer s.RUnlock()
list := make([]int, 0, len(s.m))
for item := range s.m {
list = append(list, item)
}
return list
} // 获取元素列表(有序)
func (s *Set) SortedList() []int {
s.RLock()
defer s.RUnlock()
list := make([]int, 0, len(s.m))
for item := range s.m {
list = append(list, item)
}
sort.Ints(list)
return list
} // 并集
// 获取 s 与参数的并集,结果存入 s
func (s *Set) Union(sets ...*Set) {
// 为了防止多例程死锁,不能同时锁定两个集合
// 所以这里没有锁定 s,而是创建了一个临时集合
r := s.Duplicate()
// 获取并集
for _, set := range sets {
set.Lock()
for e := range set.m {
r.m[e] = true
}
set.Unlock()
}
// 将结果转入 s
s.Lock()
defer s.Unlock()
s.m = map[int]bool{}
for e := range r.m {
s.m[e] = true
}
} // 并集(函数)
// 获取所有参数的并集,并返回
func Union(sets ...*Set) *Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取并集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
set.Lock()
for e := range set.m {
r.m[e] = true
}
set.Unlock()
}
return r
} // 差集
// 获取 s 与所有参数的差集,结果存入 s
func (s *Set) Minus(sets ...*Set) {
// 为了防止多例程死锁,不能同时锁定两个集合
// 所以这里没有锁定 s,而是创建了一个临时集合
r := s.Duplicate()
// 获取差集
for _, set := range sets {
set.Lock()
for e := range set.m {
delete(r.m, e)
}
set.Unlock()
}
// 将结果转入 s
s.Lock()
defer s.Unlock()
s.m = map[int]bool{}
for e := range r.m {
s.m[e] = true
}
} // 差集(函数)
// 获取第 1 个参数与其它参数的差集,并返回
func Minus(sets ...*Set) *Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取差集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
for e := range set.m {
delete(r.m, e)
}
}
return r
} // 交集
// 获取 s 与其它参数的交集,结果存入 s
func (s *Set) Intersect(sets ...*Set) {
// 为了防止多例程死锁,不能同时锁定两个集合
// 所以这里没有锁定 s,而是创建了一个临时集合
r := s.Duplicate()
// 获取交集
for _, set := range sets {
set.Lock()
for e := range r.m {
if _, ok := set.m[e]; !ok {
delete(r.m, e)
}
}
set.Unlock()
}
// 将结果转入 s
s.Lock()
defer s.Unlock()
s.m = map[int]bool{}
for e := range r.m {
s.m[e] = true
}
} // 交集(函数)
// 获取所有参数的交集,并返回
func Intersect(sets ...*Set) *Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取交集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
for e := range r.m {
if _, ok := set.m[e]; !ok {
delete(r.m, e)
}
}
}
return r
} // 补集
// 获取 s 相对于 full 的补集,结果存入 s
func (s *Set) Complement(full *Set) {
r := full.Duplicate()
s.Lock()
defer s.Unlock()
// 获取补集
for e := range s.m {
delete(r.m, e)
}
// 将结果转入 s
s.m = map[int]bool{}
for e := range r.m {
s.m[e] = true
}
} // 补集(函数)
// 获取 sub 相对于 full 的补集,并返回
func Complement(sub, full *Set) *Set {
r := full.Duplicate()
sub.Lock()
defer sub.Unlock()
for e := range sub.m {
delete(r.m, e)
}
return r
} func main() {
s1 := New(1, 2, 3, 4, 5, 6, 7, 8)
s2 := New(3, 4, 5, 6)
s3 := New(1, 2, 5, 6, 8, 9) // 创建 10 个 goroutine 同步操作 s2,看会不会死锁
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
for i := 0; i < 100; i++ {
s2.Union(s1) // 获取并集
fmt.Printf("%2v:s2 + %v = %v\n", n, s1.SortedList(), s2.SortedList()) s2.Minus(s3) // 获取差集
fmt.Printf("%2v:s2 - %v = %v\n", n, s3.SortedList(), s2.SortedList()) s2.Intersect(s1) // 获取交集
fmt.Printf("%2v:s2 * %v = %v\n", n, s1.SortedList(), s2.SortedList()) s2.Complement(s1) // 获取 s2 相对于 s1 的补集
fmt.Printf("%2v:%v / s2 = %v\n", n, s1.SortedList(), s2.SortedList())
}
wg.Done()
}(i)
}
wg.Wait()
} ------------------------------------------------------------
如果不用于多例程,可以使用下面的简单版本:
------------------------------------------------------------ package main import (
"fmt"
"sort"
) type Set map[int]bool // 新建集合对象
// 可以传入初始元素
func New(items ...int) Set {
s := make(Set, len(items))
s.Add(items...)
return s
} // 创建副本
func (s Set) Duplicate() Set {
r := make(map[int]bool, len(s))
for e := range s {
r[e] = true
}
return r
} // 添加元素
func (s Set) Add(items ...int) {
for _, v := range items {
s[v] = true
}
} // 删除元素
func (s Set) Remove(items ...int) {
for _, v := range items {
delete(s, v)
}
} // 判断元素是否存在
func (s Set) Has(items ...int) bool {
for _, v := range items {
if _, ok := s[v]; !ok {
return false
}
}
return true
} // 统计元素个数
func (s Set) Count() int {
return len(s)
} // 清空集合
func (s Set) Clear() {
s = map[int]bool{}
} // 空集合判断
func (s Set) Empty() bool {
return len(s) == 0
} // 获取元素列表(无序)
func (s Set) List() []int {
list := make([]int, 0, len(s))
for item := range s {
list = append(list, item)
}
return list
} // 获取元素列表(有序)
func (s Set) SortedList() []int {
list := s.List()
sort.Ints(list)
return list
} // 并集
// 获取 s 与参数的并集,结果存入 s
func (s Set) Union(sets ...Set) {
for _, set := range sets {
for e := range set {
s[e] = true
}
}
} // 并集(函数)
// 获取所有参数的并集,并返回
func Union(sets ...Set) Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取并集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
for e := range set {
r[e] = true
}
}
return r
} // 差集
// 获取 s 与所有参数的差集,结果存入 s
func (s Set) Minus(sets ...Set) {
for _, set := range sets {
for e := range set {
delete(s, e)
}
}
} // 差集(函数)
// 获取第 1 个参数与其它参数的差集,并返回
func Minus(sets ...Set) Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取差集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
for e := range set {
delete(r, e)
}
}
return r
} // 交集
// 获取 s 与其它参数的交集,结果存入 s
func (s Set) Intersect(sets ...Set) {
for _, set := range sets {
for e := range s {
if _, ok := set[e]; !ok {
delete(s, e)
}
}
}
} // 交集(函数)
// 获取所有参数的交集,并返回
func Intersect(sets ...Set) Set {
// 处理参数数量
if len(sets) == 0 {
return New()
} else if len(sets) == 1 {
return sets[0]
}
// 获取交集
r := sets[0].Duplicate()
for _, set := range sets[1:] {
for e := range r {
if _, ok := set[e]; !ok {
delete(r, e)
}
}
}
return r
} // 补集
// 获取 s 相对于 full 的补集,结果存入 s
func (s Set) Complement(full Set) {
r := s.Duplicate()
s.Clear()
for e := range full {
if _, ok := r[e]; !ok {
s[e] = true
}
}
} // 补集(函数)
// 获取 sub 相对于 full 的补集,并返回
func Complement(sub, full Set) Set {
r := full.Duplicate()
for e := range sub {
delete(r, e)
}
return r
} func main() {
s1 := New(1, 2, 3, 4, 5, 6, 7, 8)
s2 := New(3, 4, 5, 6)
s3 := New(5, 6, 8, 9)
r1 := Union(s1, s2, s3) // 获取并集
r2 := Minus(s1, s2, s3) // 获取差集
r3 := Intersect(s1, s2, s3) // 获取交集
r4 := Complement(s2, s1) // 获取 s2 相对于 s1 的补集
fmt.Println(r1.SortedList())
fmt.Println(r2.SortedList())
fmt.Println(r3.SortedList())
fmt.Println(r4.SortedList())
}
代码片段 - Golang 实现集合操作的更多相关文章
- 代码片段 - Golang 实现简单的 Web 服务器
------------------------------ 下面一段代码,实现了最简单的 Web 服务器: 编译环境: Linux Mint 18 Cinnamon 64-bit Golang 1. ...
- 代码片段 - Golang 创建 .tar.gz 压缩包
Golang创建 .tar.gz 压缩包 tar 包实现了文件的打包功能,可以将多个文件或目录存储到单一的 .tar 文件中,tar 本身不具有压缩功能,只能打包文件或目录: import " ...
- Golang, 以 9 个简短代码片段,弄懂 defer 的使用特点
作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...
- 一些日常工具集合(C++代码片段)
一些日常工具集合(C++代码片段) ——工欲善其事,必先利其器 尽管不会松松松,但是至少维持一个比较小的常数还是比较好的 在此之前依然要保证算法的正确性以及代码的可写性 本文依然会持久更新,因为一次写 ...
- golang代码片段(摘抄)
以下是从golang并发编程实战2中摘抄过来的代码片段,主要是实现一个简单的tcp socket通讯(客户端发送一个数字,服务端计算该数字的立方根然后返回),写的不错,用到了go的并发以及看下郝林大神 ...
- VSCode 如何操作用户自定义代码片段
自己写了一些根据自己习惯弄成的自定义代码片段,不喜跳过 很简单,快速过一下,F1,然后输入 snippets vue代码片段 { // Place your snippets for vue here ...
- js/jquery/html前端开发常用到代码片段
1.IE条件注释 条件注释简介 IE中的条件注释(Conditional comments)对IE的版本和IE非IE有优秀的区分能力,是WEB设计中常用的hack方法.条件注释只能用于IE5以上,IE ...
- 50个jquery代码片段(转)
本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...
- 50个必备的实用jQuery代码段+ 可以直接拿来用的15个jQuery代码片段
50个必备的实用jQuery代码段+ 可以直接拿来用的15个jQuery代码片段 本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从j ...
随机推荐
- Python 代码性能优化技巧(转)
原文:Python 代码性能优化技巧 Python 代码优化常见技巧 代码优化能够让程序运行更快,它是在不改变程序运行结果的情况下使得程序的运行效率更高,根据 80/20 原则,实现程序的重构.优化. ...
- 【转】Mysql进程管理
mysql> show processlist; +----+------+-----------+------+---------+------+-------+--------------- ...
- jBox使用方法
1.引入jquery文件 2.引入css和jBox文件 <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml& ...
- spring的annotation-driven配置事务管理器详解
http://blog.sina.com.cn/s/blog_8f61307b0100ynfb.html ——————————————————————————————————————————————— ...
- Linux下的grep搜索命令详解(二)
grep与正规表达式 字符类 字符类的搜索:如果我想要搜寻 test 或 tast 这两个单词时,可以发现到,其实她们有共通的 't?st' 存在-这个时候,我可以这样来搜寻: [root@www ...
- emWin5.24 VS2008模拟LCD12864 stm32 RTX移植 【worldsing笔记】
emWin for 12864 并口移植 源代码下载:RTX_emWin5.24_Keil_VS2008-20141122.zip 硬件环境: CPU: stm32f103ve LCD:st7 ...
- Mahout之Navie Bayesian命令端运行
landen@landen-Lenovo:~/文档/20news$ mahout trainclassifier --helpMAHOUT_LOCAL is not set; adding HADOO ...
- android 简易定时器
定时器 1.在android 应用开发当中,很多时候都要用到定时器,而要实现定时器更多的时候要用到两个类:Timer,和TimerTask 2.API对Timer的解释是:
- OC:属性、点语法、KVC
//属性的属性 属性定义在一个 .h文件里,在这个.h文件里可以定义实例变量(就是这个类的特征),也可以通过 @protery(属性约束关键字) 属性名字类型 属性名 来定义一些属性,在prope ...
- C++静态成员函数小结 [转]
类中的静态成员真是个让人爱恨交加的特性.我决定好好总结一下静态类成员的知识点,以便自己在以后面试中,在此类问题上不在被动. 静态类成员包括静态数据成员和静态函数成员两部分. 一 静态数据成员: 类体中 ...