------------------------------------------------------------
如果用于多例程,可以使用下面的版本:
------------------------------------------------------------ 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 实现集合操作的更多相关文章

  1. 代码片段 - Golang 实现简单的 Web 服务器

    ------------------------------ 下面一段代码,实现了最简单的 Web 服务器: 编译环境: Linux Mint 18 Cinnamon 64-bit Golang 1. ...

  2. 代码片段 - Golang 创建 .tar.gz 压缩包

    Golang创建 .tar.gz 压缩包 tar 包实现了文件的打包功能,可以将多个文件或目录存储到单一的 .tar 文件中,tar 本身不具有压缩功能,只能打包文件或目录: import " ...

  3. Golang, 以 9 个简短代码片段,弄懂 defer 的使用特点

    作者:林冠宏 / 指尖下的幽灵 掘金:https://juejin.im/user/587f0dfe128fe100570ce2d8 博客:http://www.cnblogs.com/linguan ...

  4. 一些日常工具集合(C++代码片段)

    一些日常工具集合(C++代码片段) ——工欲善其事,必先利其器 尽管不会松松松,但是至少维持一个比较小的常数还是比较好的 在此之前依然要保证算法的正确性以及代码的可写性 本文依然会持久更新,因为一次写 ...

  5. golang代码片段(摘抄)

    以下是从golang并发编程实战2中摘抄过来的代码片段,主要是实现一个简单的tcp socket通讯(客户端发送一个数字,服务端计算该数字的立方根然后返回),写的不错,用到了go的并发以及看下郝林大神 ...

  6. VSCode 如何操作用户自定义代码片段

    自己写了一些根据自己习惯弄成的自定义代码片段,不喜跳过 很简单,快速过一下,F1,然后输入 snippets vue代码片段 { // Place your snippets for vue here ...

  7. js/jquery/html前端开发常用到代码片段

    1.IE条件注释 条件注释简介 IE中的条件注释(Conditional comments)对IE的版本和IE非IE有优秀的区分能力,是WEB设计中常用的hack方法.条件注释只能用于IE5以上,IE ...

  8. 50个jquery代码片段(转)

    本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从jQuery1.4.2才开始支持的做法,另一些则是真正有用的函数或方法,他们能够帮助 ...

  9. 50个必备的实用jQuery代码段+ 可以直接拿来用的15个jQuery代码片段

    50个必备的实用jQuery代码段+ 可以直接拿来用的15个jQuery代码片段 本文会给你们展示50个jquery代码片段,这些代码能够给你的javascript项目提供帮助.其中的一些代码段是从j ...

随机推荐

  1. IIS启动出错解决方法

    IIS出现server application error,最终解决办法2007年10月30日 星期二 20:38Server Application Error The server has enc ...

  2. Python伪开发者对于搜狐云景的测评

    Python伪开发者对于搜狐云景的测评 本人是GAE和OpenShift的狂热爱好者,玩过各种国外PaaS.某次想搞个稍微复杂点的Python Web程序,需要比较好的网络传输速度,就试图找前PM(P ...

  3. hadoop 伪分布模式的配置

    转自 http://blog.csdn.net/zhaogezhuoyuezhao/article/details/7328313 centos系统自带ssh,版本为openssh4.3 免密码ssh ...

  4. 集群重启后启动ambari-server访问Web页面无法启动集群解决

    集群重启后启动ambari-server访问Web页面无法启动集群解决 使用ambari部署的集群重新启动后,必须手动重启ambari-server和所有集群主机上的ambari-agent. amb ...

  5. jszs 对象引用

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 【转】 ASP.NET网站路径中~(波浪线)解释

    刚开始学习ASP.NET的朋友可能会不理解路径中的-符代表什么,例如ImageUrl=”~/Images/SampleImage.jpg” 现在我们看看-代表什么意思.-是ASP.NET 的Web 应 ...

  7. [翻译]Behavior-Driven Development (BDD)行为驱动开发(二)

    测试驱动开发体现了开发人员对软件产品各部分运作方式的理解,而行为驱动开发则关注于开发人员对软件产品最终表现的行为的预期. 行为驱动开发 TDD更像是一种范式而不是一个过程.它描述了一种先编写测试,然后 ...

  8. ACM 中常用的算法有哪些? 2014-08-21 21:15 40人阅读 评论(0) 收藏

    ACM 中常用的算法有哪些?作者: 张俊Michael 网络上流传的答案有很多,估计提问者也曾经去网上搜过.所以根据自己微薄的经验提点看法. 我ACM初期是训练编码能力,以水题为主(就是没有任何算法, ...

  9. Spring中的BeanUtils与apache commons中的BeanUtils用法[1]

    1. 前言 在开发过程中,经常遇到把要给一个bean的属性赋给另外一个bean.最笨的方法是每个属性都单独写一个,聪明的方法是应用反射写一个工具方法.考虑到这个需求基本每个程序员都会遇到,那么一定已经 ...

  10. keil中如何得知所编译程序所占空间大小?

    keil编译后出现Program Size: data=21.0 xdata=0 code=2231. 这表明 data= 21.0  数据储存器内部RAM占用21字节, xdata=0     数据 ...