Skip to content

Commit

Permalink
✨ feat: add hashmap, hashset and stack unify functions #5
Browse files Browse the repository at this point in the history
  • Loading branch information
pnguyen215 committed Oct 21, 2024
1 parent 45e0348 commit 1ebde5a
Show file tree
Hide file tree
Showing 6 changed files with 1,140 additions and 0 deletions.
125 changes: 125 additions & 0 deletions hashmap.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package unify4go

// HashMap is a generic hash map data structure that maps keys of type `K` to values of type `V`.
// `K` and `V` must be comparable types, meaning that they support comparison operators (like == and !=).
// The `items` field stores the actual map, which is used to store key-value pairs.
type HashMap[K, V comparable] struct {
items map[K]V
}

// NewHashMap is a constructor function that initializes and returns a pointer to a new, empty `HashMap`.
// It creates a new map with keys of type `K` and values of type `V`.
//
// Generics are used to make this function flexible for any types of keys and values as long as they
// are comparable. The function ensures that the map is properly initialized before returning it.
//
// Example usage:
//
// hashMap := NewHashMap[string, int]() // Creates a HashMap with string keys and int values.
func NewHashMap[K, V comparable]() *HashMap[K, V] {
hash := &HashMap[K, V]{
items: make(map[K]V),
}
return hash
}

// Put adds a new key-value pair to the HashMap. If the key already exists, its value is updated.
// Parameters:
// - `key`: The key to be added or updated in the map.
// - `value`: The value to be associated with the key.
//
// Example:
//
// hashMap.Put("apple", 5) // Inserts or updates the value of "apple" to 5.
func (hash *HashMap[K, V]) Put(key K, value V) {
hash.items[key] = value
}

// Get retrieves the value associated with the given key from the HashMap.
// If the key exists, it returns the corresponding value. If the key does not exist, it returns the zero value for the type `V`.
// Parameters:
// - `key`: The key whose associated value is to be returned.
//
// Returns:
// - The value associated with the key, or the zero value for `V` if the key is not found.
//
// Example:
//
// value := hashMap.Get("apple") // Retrieves the value associated with "apple".
func (hash *HashMap[K, V]) Get(key K) (value V) {
return hash.items[key]
}

// Remove deletes the key-value pair from the HashMap for the specified key.
// If the key does not exist, no action is taken.
// Parameters:
// - `key`: The key to be removed from the map.
//
// Example:
//
// hashMap.Remove("apple") // Removes the "apple" key and its associated value.
func (hash *HashMap[K, V]) Remove(key K) {
delete(hash.items, key)
}

// Clear removes all key-value pairs from the HashMap, effectively resetting it to an empty map.
//
// Example:
//
// hashMap.Clear() // Clears the map, removing all entries.
func (hash *HashMap[K, V]) Clear() {
hash.items = make(map[K]V)
}

// Size returns the number of key-value pairs currently stored in the HashMap.
// Returns:
// - The number of key-value pairs in the map.
//
// Example:
//
// size := hashMap.Size() // Gets the size of the map.
func (hash *HashMap[K, V]) Size() int {
return len(hash.items)
}

// IsEmpty checks if the HashMap is empty (i.e., contains no key-value pairs).
// Returns:
// - `true` if the map is empty, `false` otherwise.
//
// Example:
//
// isEmpty := hashMap.IsEmpty() // Returns true if the map is empty.
func (hash *HashMap[K, V]) IsEmpty() bool {
return len(hash.items) == 0
}

// ContainsKey checks whether the specified key exists in the HashMap.
// Parameters:
// - `key`: The key to check for existence in the map.
//
// Returns:
// - `true` if the key exists in the map, `false` otherwise.
//
// Example:
//
// exists := hashMap.ContainsKey("apple") // Checks if the key "apple" exists in the map.
func (hash *HashMap[K, V]) ContainsKey(key K) bool {
_, ok := hash.items[key]
return ok
}

// KeySet returns a slice of all keys currently stored in the HashMap.
// Returns:
// - A slice containing all keys in the map.
//
// Example:
//
// keys := hashMap.KeySet() // Returns all the keys in the map.
func (hash *HashMap[K, V]) KeySet() []K {
keys := make([]K, hash.Size())
i := 0
for key := range hash.items {
keys[i] = key
}
return keys
}
234 changes: 234 additions & 0 deletions hashset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package unify4go

import "fmt"

// itemExists is an empty struct used as a placeholder for values in the `HashSet` map.
// Using an empty struct saves memory, as it does not allocate any space in Go.
var itemExists struct{}

// HashSet is a generic set data structure that stores unique elements of type `T`.
// It is implemented using a map where the keys are the elements and the values are
// empty structs (`struct{}`), which is an efficient way to represent a set in Go.
// The type `T` must be comparable, meaning it can be compared using == and !=.
type HashSet[T comparable] struct {
items map[T]struct{}
}

// NewHashSet is a constructor function that creates a new `HashSet` and optionally adds
// any provided elements to the set.
// Parameters:
// - `elements`: A variadic list of elements of type `T` to initialize the set with (optional).
//
// Returns:
// - A pointer to the newly created `HashSet`.
//
// Example usage:
//
// hashSet := NewHashSet(1, 2, 3) // Creates a set with initial elements 1, 2, and 3.
func NewHashSet[T comparable](elements ...T) *HashSet[T] {
hash := &HashSet[T]{
items: make(map[T]struct{}),
}
hash.AddAll(elements...)
return hash
}

// Add inserts a new element into the HashSet. If the element already exists, no action is taken.
// Parameters:
// - `element`: The element to be added to the set.
//
// Example usage:
//
// hashSet.Add(4) // Adds the element 4 to the set.
func (hash *HashSet[T]) Add(element T) {
hash.items[element] = itemExists
}

// AddAll inserts multiple elements into the HashSet. If any element already exists, it is ignored.
// Parameters:
// - `elements`: A variadic list of elements of type `T` to add to the set.
//
// Example usage:
//
// hashSet.AddAll(4, 5, 6) // Adds elements 4, 5, and 6 to the set.
func (hash *HashSet[T]) AddAll(elements ...T) {
for _, e := range elements {
hash.Add(e)
}
}

// Remove deletes the specified element from the HashSet.
// If the element does not exist, no action is taken.
// Parameters:
// - `element`: The element to be removed from the set.
//
// Example usage:
//
// hashSet.Remove(5) // Removes element 5 from the set.
func (hash *HashSet[T]) Remove(element T) {
delete(hash.items, element)
}

// RemoveAll deletes multiple elements from the HashSet.
// Parameters:
// - `elements`: A variadic list of elements to be removed from the set.
//
// Example usage:
//
// hashSet.RemoveAll(2, 4, 6) // Removes elements 2, 4, and 6 from the set.
func (hash *HashSet[T]) RemoveAll(elements ...T) {
for _, e := range elements {
hash.Remove(e)
}
}

// Clear removes all elements from the HashSet, resetting it to an empty set.
//
// Example usage:
//
// hashSet.Clear() // Clears all elements from the set.
func (hash *HashSet[T]) Clear() {
hash.items = make(map[T]struct{})
}

// Size returns the number of elements currently stored in the HashSet.
// Returns:
// - The number of elements in the set.
//
// Example usage:
//
// size := hashSet.Size() // Returns the size of the set.
func (hash *HashSet[T]) Size() int {
return len(hash.items)
}

// IsEmpty checks if the HashSet contains any elements.
// Returns:
// - `true` if the set is empty, `false` otherwise.
//
// Example usage:
//
// isEmpty := hashSet.IsEmpty() // Returns true if the set is empty.
func (hash *HashSet[T]) IsEmpty() bool {
return len(hash.items) == 0
}

// Contains checks whether the specified element exists in the HashSet.
// Parameters:
// - `element`: The element to check for existence in the set.
//
// Returns:
// - `true` if the element is present in the set, `false` otherwise.
//
// Example usage:
//
// exists := hashSet.Contains(3) // Checks if element 3 is in the set.
func (hash *HashSet[T]) Contains(element T) bool {
_, ok := hash.items[element]
return ok
}

// Intersection returns a new HashSet containing only the elements present in both the current set and another set.
// Parameters:
// - `another`: Another `HashSet` to find the intersection with.
//
// Returns:
// - A new `HashSet` containing the intersection of the two sets.
//
// Example usage:
//
// resultSet := hashSet.Intersection(anotherSet) // Returns the intersection of two sets.
func (hash *HashSet[T]) Intersection(another *HashSet[T]) *HashSet[T] {
result := NewHashSet[T]()
if hash.Size() <= another.Size() {
for item := range hash.items {
if _, contains := another.items[item]; contains {
result.Add(item)
}
}
return result
}
for item := range another.items {
if _, contains := hash.items[item]; contains {
result.Add(item)
}
}
return result
}

// Union returns a new HashSet that contains all elements from both the current set and another set.
// Parameters:
// - `another`: Another `HashSet` to combine with the current set.
//
// Returns:
// - A new `HashSet` containing the union of the two sets.
//
// Example usage:
//
// resultSet := hashSet.Union(anotherSet) // Returns the union of two sets.
func (hash *HashSet[T]) Union(another *HashSet[T]) *HashSet[T] {
result := NewHashSet[T]()
for item := range hash.items {
result.Add(item)
}
for item := range another.items {
result.Add(item)
}
return result
}

// Difference returns a new HashSet containing the elements that are in the current set but not in another set.
// Parameters:
// - `another`: Another `HashSet` to compare against.
//
// Returns:
// - A new `HashSet` containing the difference between the current set and the other set.
//
// Example usage:
//
// resultSet := hashSet.Difference(anotherSet) // Returns the difference between two sets.
func (hash *HashSet[T]) Difference(another *HashSet[T]) *HashSet[T] {
result := NewHashSet[T]()
for item := range hash.items {
if _, exist := another.items[item]; !exist {
result.Add(item)
}
}
return result
}

// Slice converts the HashSet into a slice of elements.
// Returns:
// - A slice containing all elements in the set.
//
// Example usage:
//
// slice := hashSet.Slice() // Converts the set to a slice.
func (hash *HashSet[T]) Slice() []T {
slices := make([]T, hash.Size())
i := 0
for val := range hash.items {
slices[i] = val
i++
}
return slices
}

// String returns a string representation of the HashSet, with elements separated by commas.
// Returns:
// - A string that represents the elements in the set.
//
// Example usage:
//
// str := hashSet.String() // Returns a string representation of the set.
func (hash *HashSet[T]) String() string {
s := ""
for val := range hash.items {
if IsEmpty(s) {
s = fmt.Sprintf("%v", val)
} else {
s = fmt.Sprintf("%s,%v", s, val)
}
}
return s
}
Loading

0 comments on commit 1ebde5a

Please sign in to comment.