代码片段 - 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 ...
随机推荐
- [WebService]之代码优先方法与契约优先方法
什么是 web 服务? web 服务是对应用程序功能的网络访问接口,它是使用标准 Internet 技术构建的. 我们目前看到的部署在 Internet 上的 web 服务都是 HTML 网站.其中, ...
- T-SQL 运行时生成语句
运行时生成语句 1.用EXECUTE执行动态命令 EXECUTE命令可以执行存储过程.函数和动态的字符串命令.注意此语句的作用正如前面在介绍批处理时,如果批中的第一条语句是"EXECUTE存 ...
- ASP.NET自定义控件入门Demo
最近看了MSDN关于自定义控件的介绍,根据官方的文档,自己学着做了一个简单的Demo给需要的朋友参考. ASP.NET 源生的TextBox是不带Label标签的,这里我要实现的是创建一个带Label ...
- Hadoop学习笔记(1)
Hadoop是什么?先问一下百度吧: [百度百科]一个分布式系统基础架构,由Apache基金会所开发.用户可以在不了解分布式底层细节的情况下,开发分布式程序.充分利用集群的威力进行高速运算和存储. H ...
- vim编辑十六进制文件
首先用二进制方式打开 vim file -b 之后输入 :%!xxd 还原为二进制文件 :%!xxd -r
- STM32中的位带(bit-band)操作
转:http://blog.csdn.net/gaojinshan/article/details/11479929 //位带操作,实现51类似的GPIO控制功能 //具体实现思想,参考<< ...
- 修改hosts文件解决OneDrive被墙的问题
增加如下内容就可以了.如果不知道修改hosts文件的具体方法请自行百度. 134.170.108.26 onedrive.live.com 134.170.108.152 skyapi.onedriv ...
- 未能加载文件或程序集“Oracle.DataAccess, Version=2.112.1.0, Culture=neutral, PublicKeyToken=89b483f429c47342”或它的某一个依赖项。 解决方法
webconfig文件对于oracle的映射错误.需要在以下位置修改 <runtime> <legacyCorruptedStateExceptionsPolicy enabled= ...
- java -X 这不是标准的选项只是为了获取帮助信息
-? -help 输出此帮助消息 获取帮助信息方式有三种: java java -? java -help -X 输出非标准选项的帮助 java -X -Xms< ...
- POJ2503——Babelfish
Description You have just moved from Waterloo to a big city. The people here speak an incomprehensib ...