diff --git a/hashtable.go b/hashtable.go index f5e5fec..26fba1d 100644 --- a/hashtable.go +++ b/hashtable.go @@ -111,6 +111,25 @@ func (hashtable *Hashtable[K, V]) AddOK(key K, value V) bool { return ok } +// Contains checks if the given value is present in the hashtable and returns the first key-value pair that matches the value. +// It takes a value as input and returns the key and a boolean indicating whether the value is found in the hashtable. +// If the value is found, it returns the corresponding key and true. If the value is not found, it returns the zero value for the key type and false. +// +// ht := make(Hashtable[string, int]) +// key, found := ht.Contains(5) // Checks if value 5 is in the hashtable, returns the key ("apple" for example) and true if found, or ("", false) if not found +func (hashtable *Hashtable[K, V]) Contains(value V) (K, bool) { + var k K + var ok bool + hashtable.EachBreak(func(key K, v V) bool { + ok = reflect.DeepEqual(v, value) + if ok { + k = key + } + return !ok + }) + return k, ok +} + // Delete removes a key-value pair from the hashtable based on the provided key. If the key exists in the hashtable, // it is deleted, and the modified hashtable is returned. If the key is not found, the hashtable remains unchanged. // @@ -248,13 +267,10 @@ func (hashtable *Hashtable[K, V]) DeleteOK(key K) bool { // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to print all key-value pairs. -// printKeyValue := func(key string, value int) { -// fmt.Println(key, value) -// } -// // // Iterate over the hashtable and print all key-value pairs. -// newHashtable.Each(printKeyValue) +// newHashtable.Each(func(key string, value int) { +// fmt.Println(key, value) +// }) // // Output: "apple 5", "banana 3", "cherry 8" func (hashtable *Hashtable[K, V]) Each(fn func(key K, value V)) *Hashtable[K, V] { return hashtable.EachBreak(func(key K, value V) bool { @@ -294,13 +310,10 @@ func (hashtable *Hashtable[K, V]) EachBreak(fn func(key K, value V) bool) *Hasht // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to print each key. -// printKey := func(key string) { -// fmt.Println(key) -// } -// // // Iterate over the hashtable and print each key. -// newHashtable.EachKey(printKey) +// newHashtable.EachKey(func(key string) { +// fmt.Println(key) +// }) // // Output: "apple", "banana", "cherry" func (hashtable *Hashtable[K, V]) EachKey(fn func(key K)) *Hashtable[K, V] { return hashtable.Each(func(key K, _ V) { @@ -315,14 +328,11 @@ func (hashtable *Hashtable[K, V]) EachKey(fn func(key K)) *Hashtable[K, V] { // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to print each key and break the iteration if the key is "banana". -// printAndBreak := func(key string) bool { +// // Iterate over the hashtable keys, print them, and break when "banana" is encountered. +// newHashtable.EachKeyBreak(func(key string) bool { // fmt.Println(key) // return key != "banana" -// } -// -// // Iterate over the hashtable keys, print them, and break when "banana" is encountered. -// newHashtable.EachKeyBreak(printAndBreak) +// }) // // Output: "apple", "banana" func (hashtable *Hashtable[K, V]) EachKeyBreak(fn func(key K) bool) *Hashtable[K, V] { return hashtable.EachBreak(func(key K, _ V) bool { @@ -337,13 +347,10 @@ func (hashtable *Hashtable[K, V]) EachKeyBreak(fn func(key K) bool) *Hashtable[K // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to print each value. -// printValue := func(value int) { -// fmt.Println(value) -// } -// // // Iterate over the hashtable values and print them. -// newHashtable.EachValue(printValue) +// newHashtable.EachValue(func(value int) { +// fmt.Println(value) +// }) // // Output: 5, 3, 8 func (hashtable *Hashtable[K, V]) EachValue(fn func(value V)) *Hashtable[K, V] { return hashtable.Each(func(_ K, value V) { @@ -359,14 +366,11 @@ func (hashtable *Hashtable[K, V]) EachValue(fn func(value V)) *Hashtable[K, V] { // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to process each value. Returns false to break the iteration if the value is 3. -// processValue := func(value int) bool { +// // Iterate over the hashtable values and process them until the value is 3. +// newHashtable.EachValueBreak(func(value int) bool { // fmt.Println(value) // return value != 3 -// } -// -// // Iterate over the hashtable values and process them until the value is 3. -// newHashtable.EachValueBreak(processValue) +// }) // // Output: 5, 3 func (hashtable *Hashtable[K, V]) EachValueBreak(fn func(value V) bool) *Hashtable[K, V] { return hashtable.EachBreak(func(_ K, value V) bool { @@ -374,6 +378,79 @@ func (hashtable *Hashtable[K, V]) EachValueBreak(fn func(value V) bool) *Hashtab }) } +// Equal checks if the current hashtable is equal to another hashtable by comparing the key-value pairs directly using reflect.DeepEqual. +// It takes another hashtable as input and returns true if the two hashtables are equal, false otherwise. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// ht1.Add("orange", 10) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("apple", 5) +// ht2.Add("orange", 10) +// +// equal := ht1.Equal(ht2) // Returns true because ht1 and ht2 have the same key-value pairs +func (hashtable *Hashtable[K, V]) Equal(otherHashtable *Hashtable[K, V]) bool { + return hashtable.EqualFunc(otherHashtable, func(a, b V) bool { + return reflect.DeepEqual(a, b) + }) +} + +// EqualFunc checks if the current hashtable is equal to another hashtable based on a provided comparison function. +// It takes another hashtable and a comparison function as input and returns true if the two hashtables are equal according to the function. +// The comparison function takes two values as input and returns true if they are considered equal, false otherwise. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// ht1.Add("orange", 10) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("apple", 5) +// ht2.Add("orange", 11) +// +// equal := ht1.EqualFunc(ht2, func(a, b int) bool { +// return math.Abs(float64(a - b)) <= 1 +// }) // Returns true because the values for "orange" (10 and 11) have a difference of 1, within the allowed range +func (hashtable *Hashtable[K, V]) EqualFunc(otherHashtable *Hashtable[K, V], fn func(a V, b V) bool) bool { + if !hashtable.EqualLength(otherHashtable) { + return false + } + for key, value := range *hashtable { + v, ok := otherHashtable.Get(key) + if !ok || !fn(value, v) { + return false + } + } + return true +} + +// EqualLength checks if the current hashtable has the same length as another hashtable. +// It takes another hashtable as input and returns true if the two hashtables have the same length, false otherwise. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// ht1.Add("orange", 10) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("apple", 5) +// +// equalLength := ht1.EqualLength(ht2) // Returns false because ht1 has a length of 2, while ht2 has a length of 1 +func (hashtable *Hashtable[K, V]) EqualLength(otherHashtable *Hashtable[K, V]) bool { + return hashtable.Length() == otherHashtable.Length() +} + +// Fetch retrieves the value associated with the given key from the hashtable. +// It returns the value if the key is found in the hashtable, and the zero value for the value type if the key is not present. +// +// ht := make(Hashtable[string, int]) +// ht.Add("apple", 5) +// value := ht.Fetch("apple") // Returns 5, the value associated with the key "apple" +// value = ht.Fetch("orange") // Returns 0 because "orange" is not in the hashtable +func (hashtable *Hashtable[K, V]) Fetch(key K) V { + value, _ := hashtable.Get(key) + return value +} + // 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. // @@ -394,13 +471,10 @@ func (hashtable *Hashtable[K, V]) Get(key K) (V, bool) { // newHashtable.Add("banana", 3) // newHashtable.Add("cherry", 8) // -// // Function to filter key-value pairs. Returns true if the value is greater than 4. -// filterFunc := func(key string, value int) bool { -// return value > 4 -// } -// // // Create a new hashtable containing key-value pairs where the value is greater than 4. -// filteredHashtable := newHashtable.Filter(filterFunc) +// filteredHashtable := newHashtable.Filter(func(key string, value int) bool { +// return value > 4 +// }) func (hashtable *Hashtable[K, V]) Filter(fn func(key K, value V) bool) *Hashtable[K, V] { filteredHashtable := make(Hashtable[K, V], 0) hashtable.Each(func(key K, value V) { @@ -469,6 +543,49 @@ func (hashtable *Hashtable[K, V]) HasMany(keys ...K) *slice.Slice[bool] { return &values } +// Intersection creates a new hashtable containing key-value pairs that exist in both the current hashtable and another hashtable. +// It compares values using reflect.DeepEqual to determine equality between the pairs. +// It takes another hashtable as input and returns a new hashtable containing the intersecting key-value pairs. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("apple", 5) +// ht2.Add("orange", 10) +// +// newHashtable := ht1.Intersection(ht2) // Creates a new hashtable with the pair "apple": 5 +func (hashtable *Hashtable[K, V]) Intersection(otherHashtable *Hashtable[K, V]) *Hashtable[K, V] { + return hashtable.IntersectionFunc(otherHashtable, func(key K, a, b V) bool { + return reflect.DeepEqual(a, b) + }) +} + +// IntersectionFunc creates a new hashtable containing key-value pairs that exist in both the current hashtable and another hashtable. +// It takes another hashtable and a condition function as input and adds key-value pairs from the current hashtable to the new hashtable +// if the condition function evaluates to true for the corresponding key-value pair in the other hashtable. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// ht1.Add("orange", 8) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("orange", 8) +// ht2.Add("banana", 6) +// +// newHashtable := ht1.IntersectionFunc(ht2, func(key string, a, b int) bool { +// return a == b +// }) // Creates a new hashtable with the pair "orange": 8 +func (hashtable *Hashtable[K, V]) IntersectionFunc(otherHashtable *Hashtable[K, V], fn func(key K, a V, b V) bool) *Hashtable[K, V] { + newHashtable := make(Hashtable[K, V], 0) + hashtable.Each(func(key K, value V) { + if v, ok := otherHashtable.Get(key); ok && fn(key, value, v) { + newHashtable.Add(key, value) + } + }) + return &newHashtable +} + // IsEmpty checks if the hashtable is empty, i.e., it contains no key-value pairs. // It returns true if the hashtable is empty and false otherwise. // @@ -540,13 +657,10 @@ func (hashtable *Hashtable[K, V]) Length() int { // newHashtable.Add("apple", 5) // newHashtable.Add("banana", 3) // -// // Function to double the values of each key-value pair. -// doubleValues := func(key string, value int) int { -// return value * 2 -// } -// // // Create a new hashtable with doubled values. -// newHashtable := newHashtable.Map(doubleValues) +// newHashtable := newHashtable.Map(func(key string, value int) int { +// return value * 2 +// }) // // New hashtable: {"apple": 10, "banana": 6} func (hashtable *Hashtable[K, V]) Map(fn func(key K, value V) V) *Hashtable[K, V] { return hashtable.MapBreak(func(key K, value V) (V, bool) { @@ -580,6 +694,45 @@ func (hashtable *Hashtable[K, V]) MapBreak(fn func(key K, value V) (V, bool)) *H return &newHashtable } +// Merge merges all key-value pairs from another hashtable into the current hashtable. +// It takes another hashtable as input and adds all its key-value pairs to the current hashtable. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("orange", 10) +// +// ht1.Merge(ht2) // Adds "orange": 10 to ht1 +func (hashtable *Hashtable[K, V]) Merge(otherHashtable *Hashtable[K, V]) *Hashtable[K, V] { + return hashtable.MergeFunc(otherHashtable, func(key K, value V) bool { return true }) +} + +// MergeFunc merges the key-value pairs from another hashtable into the current hashtable based on a provided condition function. +// It takes another hashtable and a condition function as input and adds key-value pairs from the other hashtable to the current hashtable +// if the condition function evaluates to true for the given key-value pair from the other hashtable. +// +// ht1 := make(Hashtable[string, int]) +// ht1.Add("apple", 5) +// ht1.Add("orange", 10) +// +// ht2 := make(Hashtable[string, int]) +// ht2.Add("orange", 8) +// ht2.Add("banana", 6) +// +// // Condition function to merge pairs where the value in ht2 is greater than 7 +// ht1.MergeFunc(ht2, func(key string, value int) bool { +// return value > 7 +// }) // Adds "orange": 8 to ht1, "banana": 6 does not meet the condition and is not added +func (hashtable *Hashtable[K, V]) MergeFunc(otherHashtable *Hashtable[K, V], fn func(key K, value V) bool) *Hashtable[K, V] { + otherHashtable.Each(func(key K, value V) { + if fn(key, value) { + hashtable.Add(key, value) + } + }) + return hashtable +} + // Not checks if the given key is not present in the hashtable. // It returns true if the key is not found, and false if the key exists in the hashtable. // @@ -702,10 +855,9 @@ func (hashtable *Hashtable[K, V]) Values() *slice.Slice[V] { // ht := make(Hashtable[string, int]) // ht.Add("apple", 5) // ht.Add("orange", 10) -// filterFunc := func(key string, value int) bool { +// values := ht.ValuesFunc(func(key string, value int) bool { // return value > 7 // Include values greater than 7 in the result -// } -// values := ht.ValuesFunc(filterFunc) // Returns a slice containing [10] +// }) // Returns a slice containing [10] func (hashtable *Hashtable[K, V]) ValuesFunc(fn func(key K, value V) bool) *slice.Slice[V] { values := make(slice.Slice[V], 0) hashtable.Each(func(key K, value V) { diff --git a/hashtable_test.go b/hashtable_test.go index a14bd73..877bc29 100644 --- a/hashtable_test.go +++ b/hashtable_test.go @@ -1,6 +1,7 @@ package hashtable_test import ( + "math" "reflect" "sort" "strings" @@ -181,8 +182,10 @@ func TestAddManyOK(t *testing.T) { // Test case 1: Add key-value pairs to an empty hashtable. ht := &hashtable.Hashtable[string, int]{} // Create an empty hashtable. results := ht.AddManyOK( - map[string]int{"apple": 5, "banana": 3}, - map[string]int{"banana": 10, "cherry": 8}, + map[string]int{"apple": 5}, + map[string]int{"banana": 3}, + map[string]int{"banana": 10}, + map[string]int{"cherry": 8}, ) // Verify the success status of insertions. @@ -268,6 +271,40 @@ func TestAddOK(t *testing.T) { } } +// TestContains tests Hashtable.Contains. +func TestContains(t *testing.T) { + // Test case 1: Check for a value in an empty hashtable. + ht := &hashtable.Hashtable[string, int]{} // Create an empty hashtable. + key, found := ht.Contains(5) // Check if value 5 is in the hashtable. + + // Since the hashtable is empty, the result should be ("", false). + if key != "" || found { + t.Errorf("Expected ('', false), but got (%s, %t)", key, found) + } + + // Test case 2: Check for a value in a non-empty hashtable. + ht = &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht.Add("apple", 5) + ht.Add("banana", 10) + ht.Add("orange", 5) + + // Check if value 5 is in the hashtable. + key, found = ht.Contains(5) + + // Since value 5 exists in the hashtable, the result should be ("apple", true). + if !found { + t.Errorf("Expected ('%s', true), but got (%s, %t)", key, key, found) + } + + // Test case 3: Check for a value that doesn't exist in the hashtable. + key, found = ht.Contains(15) // Check if value 15 is in the hashtable. + + // Since value 15 doesn't exist in the hashtable, the result should be ("", false). + if key != "" || found { + t.Errorf("Expected ('', false), but got (%s, %t)", key, found) + } +} + // TestDelete tests Hashtable.Delete. func TestDelete(t *testing.T) { ht := make(hashtable.Hashtable[string, int]) @@ -618,6 +655,150 @@ func TestEachValueBreak(t *testing.T) { } } +// TestEqual tests Hashtable.Equal. +func TestEqual(t *testing.T) { + // Test case 1: Compare equal hashtables. + ht1 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht1.Add("apple", 5) + ht1.Add("orange", 10) + + ht2 := &hashtable.Hashtable[string, int]{} // Create another hashtable with similar values. + ht2.Add("apple", 5) + ht2.Add("orange", 10) + + // Check if the two hashtables are equal. + equal := ht1.Equal(ht2) + + // Since ht1 and ht2 have the same key-value pairs, they are considered equal. + if !equal { + t.Errorf("Expected true, but got false") + } + + // Test case 2: Compare unequal hashtables. + ht3 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht3.Add("apple", 5) + ht3.Add("orange", 10) + + ht4 := &hashtable.Hashtable[string, int]{} // Create another hashtable with different values for "orange". + ht4.Add("apple", 5) + ht4.Add("orange", 12) + + // Check if the two hashtables are equal. + equal = ht3.Equal(ht4) + + // Since ht3 and ht4 have different values for "orange", they are not considered equal. + if equal { + t.Errorf("Expected false, but got true") + } +} + +// TestEqualFunc tests Hashtable.EqualFunc. +func TestEqualFunc(t *testing.T) { + // Custom comparison function to check if two integers are equal when their difference is less than or equal to 1 + compareFunc := func(a, b int) bool { + return math.Abs(float64(a-b)) <= 1 + } + + // Test case 1: Compare equal hashtables based on the custom comparison function. + ht1 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht1.Add("apple", 5) + ht1.Add("orange", 10) + + ht2 := &hashtable.Hashtable[string, int]{} // Create another hashtable with similar values. + ht2.Add("apple", 5) + ht2.Add("orange", 11) // The difference between 10 and 11 is within the allowed range according to compareFunc. + + // Check if the two hashtables are equal based on the custom comparison function. + equal := ht1.EqualFunc(ht2, compareFunc) + + // Since the values for "orange" (10 and 11) have a difference of 1, within the allowed range, + // the hashtables are considered equal according to the custom comparison function. + if !equal { + t.Errorf("Expected true, but got false") + } + + // Test case 2: Compare unequal hashtables based on the custom comparison function. + ht3 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht3.Add("apple", 5) + ht3.Add("orange", 10) + + ht4 := &hashtable.Hashtable[string, int]{} // Create another hashtable with different values for "orange". + ht4.Add("apple", 5) + ht4.Add("orange", 12) // The difference between 10 and 12 is greater than the allowed range according to compareFunc. + + // Check if the two hashtables are equal based on the custom comparison function. + equal = ht3.EqualFunc(ht4, compareFunc) + + // Since the difference between 10 and 12 is greater than the allowed range according to compareFunc, + // the hashtables are not considered equal based on the custom comparison function. + if equal { + t.Errorf("Expected false, but got true") + } +} + +// TestEqualLength tests Hashtable.EqualLength. +func TestEqualLength(t *testing.T) { + // Test case 1: Compare hashtables with equal length. + ht1 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht1.Add("apple", 5) + ht1.Add("orange", 10) + + ht2 := &hashtable.Hashtable[string, int]{} // Create another hashtable with the same number of key-value pairs. + ht2.Add("apple", 5) + ht2.Add("orange", 7) + + // Check if the two hashtables have equal length. + equalLength := ht1.EqualLength(ht2) + + // Since ht1 and ht2 have the same number of key-value pairs, they are considered equal in length. + if !equalLength { + t.Errorf("Expected true, but got false") + } + + // Test case 2: Compare hashtables with unequal length. + ht3 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht3.Add("apple", 5) + + ht4 := &hashtable.Hashtable[string, int]{} // Create another hashtable with a different number of key-value pairs. + ht4.Add("apple", 5) + ht4.Add("orange", 7) + + // Check if the two hashtables have equal length. + equalLength = ht3.EqualLength(ht4) + + // Since ht3 and ht4 have different numbers of key-value pairs, they are not considered equal in length. + if equalLength { + t.Errorf("Expected false, but got true") + } +} + +// TestFetch tests Hashtable.Fetch. +func TestFetch(t *testing.T) { + // Test case 1: Fetch value for an existing key. + ht := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht.Add("apple", 5) + ht.Add("orange", 10) + + // Fetch the value associated with the key "apple". + fetchedValue := ht.Fetch("apple") + + // Since "apple" is in the hashtable, the fetched value should be 5. + expectedValue := 5 + if fetchedValue != expectedValue { + t.Errorf("Expected %d, but got %d", expectedValue, fetchedValue) + } + + // Test case 2: Fetch value for a non-existing key. + // Fetch the value associated with the key "banana", which is not in the hashtable. + fetchedValue = ht.Fetch("banana") + + // Since "banana" is not in the hashtable, the fetched value should be the zero value for int, which is 0. + expectedValue = 0 + if fetchedValue != expectedValue { + t.Errorf("Expected %d, but got %d", expectedValue, fetchedValue) + } +} + // TestFilter tests Hashtable.Filter. func TestFilter(t *testing.T) { // Test case 1: Filter with an empty hashtable and a function that never selects any pairs. @@ -752,6 +933,64 @@ func TestHasMany(t *testing.T) { } } +// TestIntersectionFunc tests Hashtable.IntersectionFunc. +func TestIntersectionFunc(t *testing.T) { + // Test case: Check intersection of two hashtables with common key-value pairs. + ht1 := &hashtable.Hashtable[string, int]{ + "apple": 5, + "orange": 8, + } + ht2 := &hashtable.Hashtable[string, int]{ + "orange": 8, + "banana": 6, + } + + // Condition function to check if values are equal. + conditionFunc := func(key string, a, b int) bool { + return a == b + } + + newHashtable := ht1.IntersectionFunc(ht2, conditionFunc) + + expectedHashtable := &hashtable.Hashtable[string, int]{ + "orange": 8, + } + + if !newHashtable.Equal(expectedHashtable) { + t.Errorf("Expected intersection result to be %v, but got %v", expectedHashtable, newHashtable) + } + + // Test case: Check intersection of two hashtables with no common key-value pairs. + ht1 = &hashtable.Hashtable[string, int]{ + "apple": 5, + "orange": 8, + } + ht2 = &hashtable.Hashtable[string, int]{ + "banana": 10, + "grape": 7, + } + + newHashtable = ht1.IntersectionFunc(ht2, conditionFunc) + + expectedHashtable = &hashtable.Hashtable[string, int]{} + + if !newHashtable.Equal(expectedHashtable) { + t.Errorf("Expected intersection result to be %v, but got %v", expectedHashtable, newHashtable) + } + + // Test case: Check intersection of empty hashtables. + ht1 = &hashtable.Hashtable[string, int]{} + ht2 = &hashtable.Hashtable[string, int]{} + + newHashtable = ht1.IntersectionFunc(ht2, conditionFunc) + + expectedHashtable = &hashtable.Hashtable[string, int]{} + + if !newHashtable.Equal(expectedHashtable) { + t.Errorf("Expected intersection result to be %v, but got %v", expectedHashtable, newHashtable) + } +} + // TestKeys tests Hashtable.Keys. func TestKeys(t *testing.T) { // Create a new hashtable. @@ -881,6 +1120,61 @@ func TestMapBreak(t *testing.T) { } } +// TestMerge tests Hashtable.Merge. +func TestMerge(t *testing.T) { + // Test case: Merge all key-value pairs from another hashtable. + ht1 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht1.Add("apple", 5) + + ht2 := &hashtable.Hashtable[string, int]{} // Create another hashtable. + ht2.Add("orange", 10) + + // Merge all key-value pairs from ht2 into ht1. + ht1.Merge(ht2) + + // After merging, ht1 should contain: {"apple": 5, "orange": 10} + expectedHashtable := &hashtable.Hashtable[string, int]{ + "apple": 5, + "orange": 10, + } + + // Verify that ht1 is equal to the expected hashtable. + if !ht1.Equal(expectedHashtable) { + t.Errorf("Merge did not produce the expected result. Got: %v, Expected: %v", ht1, expectedHashtable) + } +} + +// TestMergeFunc tests Hashtable.MergeFunc. +func TestMergeFunc(t *testing.T) { + // Test case: Merge key-value pairs based on the condition function. + ht1 := &hashtable.Hashtable[string, int]{} // Create a new hashtable. + ht1.Add("apple", 5) + ht1.Add("orange", 10) + + ht2 := &hashtable.Hashtable[string, int]{} // Create another hashtable. + ht2.Add("orange", 8) + ht2.Add("banana", 6) + + // Condition function to merge pairs where the value in ht2 is greater than 7. + conditionFunc := func(key string, value int) bool { + return value > 7 + } + + // Merge key-value pairs from ht2 into ht1 based on the condition function. + ht1.MergeFunc(ht2, conditionFunc) + + // After merging, ht1 should contain: {"apple": 5, "orange": 8} + expectedHashtable := &hashtable.Hashtable[string, int]{ + "apple": 5, + "orange": 8, + } + + // Verify that ht1 is equal to the expected hashtable. + if !ht1.Equal(expectedHashtable) { + t.Errorf("MergeFunc did not produce the expected result. Got: %v, Expected: %v", ht1, expectedHashtable) + } +} + // TestNot tests Hashtable.Not. func TestNot(t *testing.T) { // Test case 1: Check if a key is not present in an empty hashtable.