------------------------------------------------------------
如果用于多例程,可以使用下面的版本:
------------------------------------------------------------ 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. 【128】Word中的VBA

    通过查找关键字,然后删除整段文字的实现! Sub 删除查找含关键词的行() Dim KeyWord As String KeyWord = InputBox("请输入关键词(词长不限,中英均 ...

  2. Servlet 2.4 规范之第一篇:概览

          写在前面的话: 本系列是对<Java Servlet Specification Version 2.4>的完全翻译,力争但不保证完美表达出英文原文的思想内涵.如有疏漏之处,还 ...

  3. POJ 1039 Pipe(直线和线段相交判断,求交点)

    Pipe Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 8280   Accepted: 2483 Description ...

  4. labview图形和图表的类型

    http://zone.ni.com/reference/zhs-XX/help/371361L-0118/lvconcepts/types_of_graphs_and_charts/ LabVIEW ...

  5. c#动态加载dll文件

    1.在写一个记录日志到文件中的类库(生成dll文件copy到一个目录中去,然后在主函数的appconfig中去配置. using System; using System.Collections.Ge ...

  6. 程序设计第三次作业--C++计算器初始部分

    面向对象程序设计作业3--C++计算器初始部分 Github 链接:https://github.com/luojingzhao/object-oriented/tree/master/calcula ...

  7. GotGitHub

    github在线教程 http://www.worldhello.net/gotgithub/

  8. So many good projects for studying C programming lanuage.

    Some one asked a question for studying C programming language on stackexachange.com. He got a bucket ...

  9. Notes on Probabilistic Latent Semantic Analysis (PLSA)

    转自:http://www.hongliangjie.com/2010/01/04/notes-on-probabilistic-latent-semantic-analysis-plsa/ I hi ...

  10. LDA(Latent Dirichlet Allocation)

    转自:http://leyew.blog.51cto.com/5043877/860255#559183-tsina-1-46862-ed0973a0c870156ed15f06a6573c8bf0 ...