Skip to content

Commit

Permalink
Dev (#22)
Browse files Browse the repository at this point in the history
* Dev
  • Loading branch information
lindsaygelle authored Oct 19, 2023
1 parent eff3638 commit abe1d06
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 19 deletions.
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)
}
}
}

0 comments on commit abe1d06

Please sign in to comment.