Skip to content

devlights/hashset

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

これは何?

Go言語用の汎用的なHashSet実装です。

Goでは標準ライブラリとしてHashSetは提供されていませんが、map[T]struct{}で同じことが出来るので基本的にそれで代用することが多いです。が、毎回同じ処理を書いているのでついでに簡易ライブラリにしたという経緯です。

インストール

go get github.com/devlights/hashset@latest

クイックスタート

package main

import (
    "fmt"
    "github.com/devlights/hashset"
)

func main() {
    // 新しい文字列集合を作成
    fruits := hashset.New[string]()
    
    // 要素を追加
    fruits.Add("apple")
    fruits.Add("banana")
    fruits.Add("orange")
    
    // 要素の存在を確認
    fmt.Println(fruits.Contains("apple")) // true
    fmt.Println(fruits.Contains("grape")) // false
    
    // サイズを取得
    fmt.Printf("集合のサイズ: %d\n", fruits.Size()) // 集合のサイズ: 3
    
    // スライスに変換
    fruitsSlice := fruits.ToSlice()
    fmt.Printf("フルーツ: %v\n", fruitsSlice)
}

API リファレンス

作成

// 空の集合を作成
set := hashset.New[string]()

// 初期容量を指定して作成(パフォーマンス最適化のため)
set := hashset.NewWithCapacity[string](100)

// スライスから作成
items := []string{"apple", "banana", "orange"}
set := hashset.NewFromSlice(items)

基本操作

// 単一要素を追加
set.Add("apple")

// 複数要素を追加
set.AddAll([]string{"banana", "orange"})

// 単一要素を削除
set.Remove("apple")

// 複数要素を削除
set.RemoveAll([]string{"banana", "orange"})

// 存在確認
exists := set.Contains("apple")

// 複数要素の確認
allExist := set.ContainsAll([]string{"apple", "banana"})
anyExist := set.ContainsAny([]string{"apple", "grape"})

// サイズ取得と空かどうかの確認
size := set.Size()
empty := set.IsEmpty()

// すべての要素をクリア
set.Clear()

変換と複製

// スライスに変換
slice := set.ToSlice()

// コピーを作成
clone := set.Clone()

集合演算

set1 := hashset.NewFromSlice([]string{"apple", "banana"})
set2 := hashset.NewFromSlice([]string{"banana", "orange"})

// 和集合 (A ∪ B)
union := set1.Union(set2) // {"apple", "banana", "orange"}

// 積集合 (A ∩ B)
intersection := set1.Intersection(set2) // {"banana"}

// 差集合 (A - B)
difference := set1.Difference(set2) // {"apple"}

// 対称差集合 ((A ∪ B) - (A ∩ B))
symDiff := set1.SymmetricDifference(set2) // {"apple", "orange"}

集合関係

set1 := hashset.NewFromSlice([]string{"apple", "banana"})
set2 := hashset.NewFromSlice([]string{"apple", "banana", "orange"})

// set1がset2の部分集合かどうかを確認
isSubset := set1.IsSubsetOf(set2) // true

// set2がset1の上位集合かどうかを確認
isSuperset := set2.IsSupersetOf(set1) // true

// 集合が共通要素を持たないかどうかを確認
disjoint := set1.IsDisjoint(hashset.NewFromSlice([]string{"grape", "kiwi"})) // true

// 集合が等しいかどうかを確認
equal := set1.Equal(set1.Clone()) // true

反復処理

// 要素を反復処理
for item := range set.All() {
    fmt.Println(item)
}

使用例

異なる型での使用

// 文字列集合
fruits := hashset.NewFromSlice([]string{"apple", "banana", "orange"})

// 整数集合
numbers := hashset.NewFromSlice([]int{1, 2, 3, 4, 5})

// カスタム構造体(比較可能である必要があります)
type Person struct {
    Name string
    Age  int
}

people := hashset.New[Person]()
people.Add(Person{Name: "Alice", Age: 30})
people.Add(Person{Name: "Bob", Age: 25})

共通要素の検索

users1 := hashset.NewFromSlice([]string{"alice", "bob", "charlie"})
users2 := hashset.NewFromSlice([]string{"bob", "david", "eve"})
users3 := hashset.NewFromSlice([]string{"bob", "frank", "grace"})

// 3つすべての集合に共通するユーザーを検索
common := users1.Intersection(users2).Intersection(users3)
fmt.Println("共通ユーザー:", common.ToSlice()) // [bob]

スライスから重複を除去

func removeDuplicates[T comparable](slice []T) []T {
    set := hashset.NewFromSlice(slice)
    return set.ToSlice()
}

// 使用例
numbers := []int{1, 2, 2, 3, 3, 3, 4, 5}
unique := removeDuplicates(numbers)
// unique には [1, 2, 3, 4, 5] が含まれます(順序は保証されません)

集合ベースのデータ処理

// ユーザー権限の処理
adminUsers := hashset.NewFromSlice([]string{"alice", "bob"})
activeUsers := hashset.NewFromSlice([]string{"alice", "charlie", "david"})
bannedUsers := hashset.NewFromSlice([]string{"eve", "frank"})

// アクティブな管理者ユーザーを検索
activeAdmins := adminUsers.Intersection(activeUsers)

// システムにアクセス可能なユーザーを検索(アクティブでかつ禁止されていない)
allowedUsers := activeUsers.Difference(bannedUsers)

// いずれかのカテゴリに言及されているすべてのユーザーを検索
allUsers := adminUsers.Union(activeUsers).Union(bannedUsers)

スレッドセーフティ

この実装はスレッドセーフではありません。並行アクセスが必要な場合は、適切な同期処理でラップしてください:

import "sync"

type SafeSet[T comparable] struct {
    set hashset.Set[T]
    mu  sync.RWMutex
}

func NewSafeSet[T comparable]() *SafeSet[T] {
    return &SafeSet[T]{
        set: hashset.New[T](),
    }
}

func (s *SafeSet[T]) Add(item T) {
    s.mu.Lock()
    defer s.mu.Unlock()
    s.set.Add(item)
}

func (s *SafeSet[T]) Contains(item T) bool {
    s.mu.RLock()
    defer s.mu.RUnlock()
    return s.set.Contains(item)
}

About

Go言語用の汎用的なHashSet実装です。

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages