From d2d1b99458b21ccc4ad22da9f16ad8586d6b1a91 Mon Sep 17 00:00:00 2001 From: Linneeeeeeee Date: Tue, 17 Oct 2023 12:13:39 +1100 Subject: [PATCH] Dev (#16) * Dev --- go.mod | 2 +- hashtable.go | 73 ++++++++++++++++++++++++++ hashtable_test.go | 131 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 205 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index aefac74..b4fed8d 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/lindsaygelle/hashtable -go 1.21.1 +go 1.21 diff --git a/hashtable.go b/hashtable.go index c1b8cfc..4ed763f 100644 --- a/hashtable.go +++ b/hashtable.go @@ -33,3 +33,76 @@ func (hashtable *Hashtable[K, V]) Add(key K, value V) *Hashtable[K, V] { (*hashtable)[key] = value return hashtable } + +// AddFunc inserts key-value pairs into the hashtable based on the provided maps and a custom validation function. +// The validation function should return true for key-value pairs that should be added to the hashtable, and false otherwise. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.AddFunc([]map[string]int{{"apple": 1, "orange": 2}}, func(key string, value int) bool { +// // Only add key-value pairs where the value is greater than 1. +// return value > 1 +// }) +func (hashtable *Hashtable[K, V]) AddFunc(values []map[K]V, fn func(key K, value V) bool) *Hashtable[K, V] { + for _, item := range values { + for key, value := range item { + if fn(key, value) { + hashtable.Add(key, value) + } + } + } + return hashtable +} + +// AddMany inserts multiple key-value pairs into the hashtable from the provided maps. +// If keys already exist, their associated values are updated. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.AddMany(map[string]int{"orange": 7, "grape": 4}, map[string]int{"kiwi": 6, "pear": 9}) +func (hashtable *Hashtable[K, V]) AddMany(values ...map[K]V) *Hashtable[K, V] { + for _, item := range values { + for key, value := range item { + hashtable.Add(key, value) + } + } + return hashtable +} + +// Delete removes a key-value pair from the hashtable based on the provided key. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.Add("apple", 5) +// ht.Add("banana", 3) +// ht.Delete("apple") // Removes the key-value pair with key "apple" from the hashtable. +func (hashtable *Hashtable[K, V]) Delete(key K) *Hashtable[K, V] { + delete(*hashtable, key) + return hashtable +} + +// Get retrieves the value associated with the provided key from the hashtable. +// If the key exists, it returns the associated value and true. Otherwise, it returns the zero value for the value type and false. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.Add("apple", 5) +// value, exists := ht.Get("apple") // 5, true +// value, exists = ht.Get("orange") // 0, false +func (hashtable *Hashtable[K, V]) Get(key K) (V, bool) { + value, ok := (*hashtable)[key] + return value, ok +} + +// Has checks if the provided key exists in the hashtable. +// It returns true if the key exists, and false otherwise. +// +// Example: +// ht := make(hashtable.Hashtable[string, int]) +// ht.Add("apple", 5) +// exists := ht.Has("apple") // true +// exists = ht.Has("orange") // false +func (hashtable *Hashtable[K, V]) Has(key K) bool { + _, ok := (*hashtable)[key] + return ok +} diff --git a/hashtable_test.go b/hashtable_test.go index 47f64fa..12d0f53 100644 --- a/hashtable_test.go +++ b/hashtable_test.go @@ -47,3 +47,134 @@ func TestAdd(t *testing.T) { t.Fatalf("Expected value for key 'banana' to be updated to 10, but got %d", ht["banana"]) } } + +// TestAddFunc tests Hashtable.AddFunc. +func TestAddFunc(t *testing.T) { + ht := make(hashtable.Hashtable[string, int]) + + // Test case 1: Add key-value pairs where the value is greater than 1 + ht.AddFunc([]map[string]int{{"apple": 1, "orange": 2, "banana": 3}}, func(key string, value int) bool { + return value > 1 + }) + + // Check if expected key-value pairs are added + expected := map[string]int{"orange": 2, "banana": 3} + for key, expectedValue := range expected { + value, exists := ht.Get(key) + if !exists || value != expectedValue { + t.Errorf("Expected key '%s' with value '%d', but got value '%d'", key, expectedValue, value) + } + } + + // Test case 2: Add all key-value pairs without any validation + ht.AddFunc([]map[string]int{{"kiwi": 0, "pear": 4}}, func(key string, value int) bool { + return true + }) + + // Check if all key-value pairs are added + allValues := map[string]int{"orange": 2, "banana": 3, "kiwi": 0, "pear": 4} + for key, expectedValue := range allValues { + value, exists := ht.Get(key) + if !exists || value != expectedValue { + t.Errorf("Expected key '%s' with value '%d', but got value '%d'", key, expectedValue, value) + } + } +} + +// TestAddMany tests Hashtable.AddMany + +func TestAddMany(t *testing.T) { + ht := make(hashtable.Hashtable[string, int]) + + // Test case 1 + ht.AddMany(map[string]int{"orange": 7, "grape": 4}) + expected1 := 7 + if val, ok := ht["orange"]; !ok || val != expected1 { + t.Errorf("Expected %d, but got %d for key 'orange'", expected1, val) + } + expected2 := 4 + if val, ok := ht["grape"]; !ok || val != expected2 { + t.Errorf("Expected %d, but got %d for key 'grape'", expected2, val) + } + + // Test case 2 + ht.AddMany(map[string]int{"kiwi": 6, "pear": 9}) + expected3 := 6 + if val, ok := ht["kiwi"]; !ok || val != expected3 { + t.Errorf("Expected %d, but got %d for key 'kiwi'", expected3, val) + } + expected4 := 9 + if val, ok := ht["pear"]; !ok || val != expected4 { + t.Errorf("Expected %d, but got %d for key 'pear'", expected4, val) + } +} + +// TestDelete tests Hashtable.Delete +func TestDelete(t *testing.T) { + ht := make(hashtable.Hashtable[string, int]) + ht["apple"] = 5 + ht["banana"] = 3 + + // Test case 1: Delete an existing key + ht.Delete("apple") + if _, ok := ht["apple"]; ok { + t.Errorf("Expected key 'apple' to be deleted, but it still exists in the hashtable") + } + + // Test case 2: Delete a non-existing key + ht.Delete("nonexistent") + if _, ok := ht["nonexistent"]; ok { + t.Errorf("Expected key 'nonexistent' to not exist, but it was found in the hashtable") + } + + // Test case 3: Delete a key after adding it again + ht["apple"] = 10 + ht.Delete("apple") + if _, ok := ht["apple"]; ok { + t.Errorf("Expected key 'apple' to be deleted, but it still exists in the hashtable") + } +} + +// TestGet tests Hashtable.Get + +func TestGet(t *testing.T) { + ht := make(hashtable.Hashtable[string, int]) + ht["apple"] = 5 + ht["banana"] = 3 + + // Test case 1: Get an existing key + value, exists := ht.Get("apple") + if !exists { + t.Errorf("Expected key 'apple' to exist, but it was not found in the hashtable") + } + if value != 5 { + t.Errorf("Expected value for key 'apple' to be 5, but got %d", value) + } + + // Test case 2: Get a non-existing key + value, exists = ht.Get("orange") + if exists { + t.Errorf("Expected key 'orange' to not exist, but it was found in the hashtable with value %d", value) + } + if value != 0 { + t.Errorf("Expected default value for non-existing key 'orange' to be 0, but got %d", value) + } +} + +// TestHas tests Hashtable.Has + +func TestHas(t *testing.T) { + ht := make(hashtable.Hashtable[string, int]) + ht["apple"] = 5 + ht["banana"] = 3 + + // Test case 1: Key exists in the hashtable + if !ht.Has("apple") { + t.Errorf("Expected key 'apple' to exist, but it was not found in the hashtable") + } + + // Test case 2: Key does not exist in the hashtable + if ht.Has("orange") { + t.Errorf("Expected key 'orange' to not exist, but it was found in the hashtable") + } +}