Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev #22

Merged
merged 3 commits into from
Oct 19, 2023
Merged

Dev #22

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 89 additions & 19 deletions hashtable.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,29 @@ func (hashtable *Hashtable[K, V]) AddMany(values ...map[K]V) *Hashtable[K, V] {
return hashtable
}

// AddManyOK inserts multiple key-value pairs into the hashtable and returns a slice of booleans indicating
// whether each insertion was successful. If a key already exists, it is not updated, and the corresponding
// boolean value is set to false in the returned slice.
//
// Example:
//
// ht := make(hashtable.Hashtable[string, int])
// results := ht.AddManyOK(
// map[string]int{"apple": 5, "banana": 3},
// map[string]int{"banana": 10, "cherry": 8},
// )
// // results contains [true, false, true] indicating successful insertions for "apple" and "cherry"
// // and unsuccessful insertion for "banana" due to existing key.
func (hashtable *Hashtable[K, V]) AddManyOK(values ...map[K]V) *slice.Slice[bool] {
successfulInsertions := make(slice.Slice[bool], 0)
for _, item := range values {
for key, value := range item {
successfulInsertions.Append(hashtable.AddOK(key, value))
}
}
return &successfulInsertions
}

// AddOK inserts a new key-value pair into the hashtable if the key does not already exist.
// It returns a boolean value indicating whether the key was added successfully (true) or if the key already existed (false).
//
Expand Down Expand Up @@ -179,6 +202,27 @@ func (hashtable *Hashtable[K, V]) DeleteMany(keys ...K) *Hashtable[K, V] {
return hashtable
}

// DeleteManyOK deletes multiple keys from the hashtable and returns a slice of booleans indicating whether each deletion was successful.
// For each specified key, it checks if the key exists in the hashtable before attempting deletion. If the key does not exist,
// the deletion is considered unsuccessful for that key, and false is appended to the returned slice. If the key exists and is successfully
// deleted, true is appended; otherwise, false is appended.
//
// Example:
//
// ht := make(hashtable.Hashtable[string, int])
// ht.Add("apple", 5)
// ht.Add("banana", 3)
// keysToDelete := []string{"apple", "grape"}
// results := ht.DeleteManyOK(keysToDelete...)
// // results contains [true, true], indicating successful deletion of "apple" (exists) and "grape" (does not exist)
func (hashtable *Hashtable[K, V]) DeleteManyOK(keys ...K) *slice.Slice[bool] {
deletetions := make(slice.Slice[bool], 0)
for _, key := range keys {
deletetions.Append(hashtable.DeleteOK(key))
}
return &deletetions
}

// DeleteManyValues deletes key-value pairs from the hashtable where the value matches any of the specified values.
//
// Example:
Expand All @@ -197,13 +241,26 @@ func (hashtable *Hashtable[K, V]) DeleteManyValues(values ...V) *Hashtable[K, V]
for _, v := range values {
if reflect.DeepEqual(v, value) {
hashtable.Delete(key)
break
}
}
}
return hashtable
}

// DeleteOK deletes the specified key from the hashtable and returns a boolean indicating whether the deletion was successful.
// If the key does not exist in the hashtable, it is considered a successful deletion, and true is returned.
//
// Example:
//
// ht := make(hashtable.Hashtable[string, int])
// ht.Add("apple", 5)
// ht.Add("banana", 3)
// deleted := ht.DeleteOK("apple") // true, "apple" key is successfully deleted
// notDeleted := ht.DeleteOK("grape") // true, "grape" key does not exist, deletion is considered successful
func (hashtable *Hashtable[K, V]) DeleteOK(key K) bool {
return !hashtable.Delete(key).Has(key)
}

// Each iterates over the key-value pairs in the hashtable and applies a function to each pair.
//
// Example:
Expand Down Expand Up @@ -483,38 +540,51 @@ func (hashtable *Hashtable[K, V]) Length() int {
return len(*hashtable)
}

// Map applies a given function to all key-value pairs in the hashtable and returns a new hashtable with the transformed values.
// The original hashtable remains unchanged.
// Map iterates over the key-value pairs in the hashtable and applies the provided function to each pair.
// The function can modify the value. The modified key-value pairs are updated in the same hashtable.
//
// Example:
//
// ht := make(hashtable.Hashtable[string, int])
// ht.Add("apple", 5)
// ht.Add("banana", 3)
// ht.Add("cherry", 8)
//
// // Define a function to double the values.
// doubleValue := func(key string, value int) int {
// return value * 2
// }
//
// // Apply the function to double the values in the hashtable.
// doubledHT := ht.Map(doubleValue)
// // doubledHT contains: {"apple": 10, "banana": 6, "cherry": 16}
// ht.Map(func(key string, value int) int {
// if key == "banana" {
// return value * 2 // Modify the value for the "banana" key
// }
// return value // Leave other values unchanged
// })
// // ht: {"apple": 5, "banana": 6}
func (hashtable *Hashtable[K, V]) Map(fn func(key K, value V) V) *Hashtable[K, V] {
for key, value := range *hashtable {
hashtable.Add(key, fn(key, value))
}
return hashtable
return hashtable.MapBreak(func(key K, value V) (V, bool) {
return fn(key, value), true
})
}

// MapBreak iterates over the key-value pairs in the hashtable and applies the provided function to each pair.
// The function can modify the value and return a boolean indicating whether to continue the iteration.
// If the function returns false, the iteration breaks, and a new hashtable with modified key-value pairs is returned.
//
// Example:
//
// ht := make(hashtable.Hashtable[string, int])
// ht.Add("apple", 5)
// ht.Add("banana", 3)
// newHT := ht.MapBreak(func(key string, value int) (int, bool) {
// if key == "banana" {
// return value * 2, false // Break the iteration when key is "banana"
// }
// return value, true // Continue iterating for other keys
// })
// // newHT: {"apple": 5}
func (hashtable *Hashtable[K, V]) MapBreak(fn func(key K, value V) (V, bool)) *Hashtable[K, V] {
newHashtable := make(Hashtable[K, V])
for key, value := range *hashtable {
value, ok := fn(key, value)
if !ok {
break
}
hashtable.Add(key, value)
newHashtable.Add(key, value)
}
return hashtable
return &newHashtable
}
153 changes: 153 additions & 0 deletions hashtable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,42 @@ func TestAddMany(t *testing.T) {
}
}

// TestAddManyOK tests Hashtable.AddManyOK.
func TestAddManyOK(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])

// Attempt to add multiple key-value pairs and get the results indicating success.
results := ht.AddManyOK(
map[string]int{"apple": 5, "banana": 3, "cherry": 8},
)

// Expected results: [true, true, true] indicating successful insertions for "apple", "banana" and "cherry".
expectedResults := []bool{true, true, true}

// Verify that the obtained results match the expected results.
for i, result := range *results {
if result != expectedResults[i] {
t.Fatalf("Expected result: %v, but got: %v", expectedResults[i], result)
}
}

// Attempt to add multiple key-value pairs and get the results indicating success.
results = ht.AddManyOK(
map[string]int{"apple": 5, "banana": 3, "cherry": 8},
)

// Expected results: [false, false, false] indicating unsuccessful insertions for "apple", "banana" and "cherry" due to existing key.
expectedResults = []bool{false, false, false}

// Verify that the obtained results match the expected results.
for i, result := range *results {
if result != expectedResults[i] {
t.Fatalf("Expected result: %v, but got: %v", expectedResults[i], result)
}
}
}

// TestAddOK tests Hashtable.AddOK.
func TestAddOK(t *testing.T) {
ht := make(hashtable.Hashtable[string, int])
Expand Down Expand Up @@ -313,6 +349,7 @@ func TestDeleteMany(t *testing.T) {
}
}

// TestDeleteManyValues tests Hashtable.DeleteManyValues.
func TestDeleteManyValues(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])
Expand All @@ -330,6 +367,59 @@ func TestDeleteManyValues(t *testing.T) {
}
}

// TestDeleteManyOK tests Hashtable.DeleteManyOK.
func TestDeleteManyOK(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])

// Add key-value pairs to the hashtable.
ht.Add("apple", 5)
ht.Add("banana", 3)

// Specify keys to delete.
keysToDelete := []string{"apple", "grape"}

// Attempt to delete keys and check if deletion is successful.
results := ht.DeleteManyOK(keysToDelete...)

expectedResults := []bool{true, true} // Expected results for "apple" (exists) and "grape" (does not exist)

// Check if results match the expected results.
for i, result := range *results {
if result != expectedResults[i] {
t.Fatalf("Expected deletion of key %s to be %v but got %v", keysToDelete[i], expectedResults[i], result)
}
}
}

// TestDeleteOK tests Hashtable.DeleteOK.
func TestDeleteOK(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])

// Add key-value pairs to the hashtable.
ht.Add("apple", 5)
ht.Add("banana", 3)

// Delete keys and check if deletion is successful.
deleted := ht.DeleteOK("apple")
if !deleted {
t.Fatalf("Expected deletion of 'apple' to be successful")
}

// Attempt to delete a key that does not exist.
notDeleted := ht.DeleteOK("grape")
if !notDeleted {
t.Fatalf("Expected deletion of 'grape' to be successful because the key does not exist")
}

// Attempt to delete a key that has already been deleted.
alreadyDeleted := ht.DeleteOK("apple")
if !alreadyDeleted {
t.Fatalf("Expected deletion of 'apple' to be successful even though it was already deleted")
}
}

// TestEach tests Hashtable.Each.
func TestEach(t *testing.T) {
ht := make(hashtable.Hashtable[string, int])
Expand Down Expand Up @@ -639,6 +729,7 @@ func TestKeys(t *testing.T) {
}
}

// TestKeysFunc tests Hashtable.Keys.
func TestKeysFunc(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])
Expand All @@ -660,6 +751,7 @@ func TestKeysFunc(t *testing.T) {
}
}

// TestLength tests Hashtable.Length.
func TestLength(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])
Expand All @@ -678,3 +770,64 @@ func TestLength(t *testing.T) {
t.Fatalf("Expected length: %d, but got: %d", expectedLength, length)
}
}

func TestMap(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])

// Add key-value pairs to the hashtable.
ht["apple"] = 5
ht["banana"] = 3
ht["cherry"] = 8

// Define a function to double the values.
doubleValue := func(key string, value int) int {
return value * 2
}

// Apply the function to double the values in the hashtable.
doubledHT := ht.Map(doubleValue)

// Expected doubled values.
expectedValues := map[string]int{"apple": 10, "banana": 6, "cherry": 16}
for key, expectedValue := range expectedValues {
value, exists := (*doubledHT)[key]
if !exists || value != expectedValue {
t.Fatalf("Expected value %d for key %s, but got %d", expectedValue, key, value)
}
}

// Ensure the original hashtable remains unchanged.
for key, expectedValue := range expectedValues {
value, exists := ht[key]
if !exists || value != expectedValue/2 {
t.Fatalf("Expected original value %d for key %s, but got %d", expectedValue/2, key, value)
}
}
}

// TestMapBreak tests Hashtable.MapBreak.
func TestMapBreak(t *testing.T) {
// Create a new hashtable.
ht := make(hashtable.Hashtable[string, int])

// Add key-value pairs to the hashtable.
ht["banana"] = 3

// Apply the MapBreak function to modify values and break the iteration at "banana".
ht.MapBreak(func(key string, value int) (int, bool) {
if key == "banana" {
return value * 2, false // Break the iteration when key is "banana"
}
return value * 2, true // Continue iterating for other keys and double the values
})

// Check if values are not modified as expected.
expectedValues := map[string]int{"banana": 3}
for key, expectedValue := range expectedValues {
value, exists := ht.Get(key)
if !exists || value != expectedValue {
t.Fatalf("Expected value %d for key %s, but got %d", expectedValue, key, value)
}
}
}
Loading