Skip to content
87 changes: 86 additions & 1 deletion queue/ArrayQueue/arrayqueue.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package arrayqueue

import dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error"
import (
dsa_error "github.com/hmcalister/Go-DSA/utils/DSA_Error"
)

// Implement a queue using a array / slice.
//
Expand Down Expand Up @@ -96,3 +98,86 @@ func (queue *ArrayQueue[T]) Remove() (T, error) {
queue.queueData = queue.queueData[1:]
return item, nil
}

// ----------------------------------------------------------------------------
// Apply, Map, and Fold methods
//
// Methods to apply a function across ALL items in a queue.

// Iterate over the queue in the forward direction and apply a function to each item.
//
// It is expected that ForwardApply does *not* update the queue items.
// To modify the queue items, use ForwardMap.
// To accumulate values over the queue, use ForwardFold.
func ForwardApply[T any](queue *ArrayQueue[T], f func(item T)) {
for index := 0; index < len(queue.queueData); index += 1 {
f(queue.queueData[index])
}
}

// Iterate over the queue in the forward direction and apply a function to each item
// The result of this function is then assigned to the node at each step.
//
// ForwardMap can update the node items by returning the update value.
// If you do not need to modify the queue items, use ForwardApply.
// To accumulate values over the queue, use ForwardFold.
func ForwardMap[T any](queue *ArrayQueue[T], f func(item T) T) {
for index := 0; index < len(queue.queueData); index += 1 {
queue.queueData[index] = f(queue.queueData[index])
}
}

// Iterate over the queue and apply the function f to it.
// The function f also takes the current value of the accumulator.
// The results of f become the new value of the accumulator at each step.
//
// This function returns the final accumulator.
//
// This function is not a method on ArrayQueue to allow for generic accumulators.
func ForwardFold[T any, G any](queue *ArrayQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G {
accumulator := initialAccumulator
for index := 0; index < len(queue.queueData); index += 1 {
accumulator = f(queue.queueData[index], accumulator)
}

return accumulator
}

// Iterate over the queue in the reverse direction and apply a function to each item.
//
// It is expected that ReverseApply does *not* update the queue items.
// To modify the queue items, use ReverseMap.
// To accumulate values over the queue, use ReverseFold.
func ReverseApply[T any](queue *ArrayQueue[T], f func(item T)) {
for index := len(queue.queueData) - 1; index >= 0; index -= 1 {
f(queue.queueData[index])
}
}

// Iterate over the queue in the reverse direction and apply a function to each item
// The result of this function is then assigned to the node at each step.
//
// ReverseMap can update the node items by returning the update value.
// If you do not need to modify the queue items, use ReverseApply.
// To accumulate values over the queue, use ReverseFold.
func ReverseMap[T any](queue *ArrayQueue[T], f func(item T) T) {
for index := len(queue.queueData) - 1; index >= 0; index -= 1 {
queue.queueData[index] = f(queue.queueData[index])
}
}

// Iterate over the queue and apply the function f to it.
// The function f also takes the current value of the accumulator.
// The results of f become the new value of the accumulator at each step.
//
// This function returns the final accumulator.
//
// This function is not a method on ArrayQueue to allow for generic accumulators.
func ReverseFold[T any, G any](queue *ArrayQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G {
accumulator := initialAccumulator
for index := len(queue.queueData) - 1; index >= 0; index -= 1 {
accumulator = f(queue.queueData[index], accumulator)
}

return accumulator
}
122 changes: 122 additions & 0 deletions queue/ArrayQueue/arrayqueue_apply_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package arrayqueue_test

import (
"fmt"
"slices"
"testing"

arrayqueue "github.com/hmcalister/Go-DSA/queue/ArrayQueue"
)

func TestForwardApply(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

concatString := ""
arrayqueue.ForwardApply(queue, func(item string) { concatString += item })
expectedConcatString := ""
for _, item := range items {
expectedConcatString += item
}

if concatString != expectedConcatString {
t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString)
}
}

func TestReverseApply(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

concatString := ""
arrayqueue.ReverseApply(queue, func(item string) { concatString += item })

slices.Reverse(items)
expectedConcatString := ""
for _, item := range items {
expectedConcatString += item
}

if concatString != expectedConcatString {
t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString)
}
}

func TestForwardMap(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

globalCounter := 0
arrayqueue.ForwardMap(queue, func(item string) string {
newItem := fmt.Sprintf("%v, %v", item, globalCounter)
globalCounter += 1
return newItem
})
}

func TestReverseMap(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

globalCounter := 0
arrayqueue.ReverseMap(queue, func(item string) string {
newItem := fmt.Sprintf("%v, %v", item, globalCounter)
globalCounter += 1
return newItem
})

}

func TestForwardFold(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

concatString := arrayqueue.ForwardFold(queue, "", func(item string, accumulator string) string {
return accumulator + item
})
expectedConcatString := ""
for _, item := range items {
expectedConcatString += item
}

if concatString != expectedConcatString {
t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString)
}
}

func TestReverseFold(t *testing.T) {
queue := arrayqueue.New[string]()
items := []string{"a", "b", "c", "d", "e", "f", "g", "h"}
for _, item := range items {
queue.Add(item)
}

concatString := arrayqueue.ReverseFold(queue, "", func(item string, accumulator string) string {
return accumulator + item
})

slices.Reverse(items)
expectedConcatString := ""
for _, item := range items {
expectedConcatString += item
}

if concatString != expectedConcatString {
t.Errorf("result (%v) does not match expected result (%v)", concatString, expectedConcatString)
}
}
77 changes: 77 additions & 0 deletions queue/LinkedListQueue/linkedlistqueue.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,80 @@ func (queue *LinkedListQueue[T]) Remove() (T, error) {

return queue.queueData.RemoveAtIndex(0)
}

// ----------------------------------------------------------------------------
// Apply, Map, and Fold methods
//
// Methods to apply a function across ALL items in a queue.

// Iterate over the queue in the forward direction and apply a function to each item.
//
// It is expected that ForwardApply does *not* update the queue items.
// To modify the queue items, use ForwardMap.
// To accumulate values over the queue, use ForwardFold.
//
// Internally, this method calls linkedlist.ForwardApply
func ForwardApply[T any](queue *LinkedListQueue[T], f func(item T)) {
linkedlist.ForwardApply(queue.queueData, f)
}

// Iterate over the queue in the forward direction and apply a function to each item
// The result of this function is then assigned to the node at each step.
//
// ForwardMap can update the node items by returning the update value.
// If you do not need to modify the queue items, use ForwardApply.
// To accumulate values over the queue, use ForwardFold.
//
// Internally, this method calls linkedlist.ForwardMap
func ForwardMap[T any](queue *LinkedListQueue[T], f func(item T) T) {
linkedlist.ForwardMap(queue.queueData, f)
}

// Iterate over the queue and apply the function f to it.
// The function f also takes the current value of the accumulator.
// The results of f become the new value of the accumulator at each step.
//
// This function returns the final accumulator.
//
// This function is not a method on LinkedListQueue to allow for generic accumulators.
//
// Internally, this method calls linkedlist.ForwardFold
func ForwardFold[T any, G any](queue *LinkedListQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G {
return linkedlist.ForwardFold(queue.queueData, initialAccumulator, f)
}

// Iterate over the queue in the reverse direction and apply a function to each item.
//
// It is expected that ReverseApply does *not* update the queue items.
// To modify the queue items, use ReverseMap.
// To accumulate values over the queue, use ReverseFold.
//
// Internally, this method calls linkedlist.ReverseApply
func ReverseApply[T any](queue *LinkedListQueue[T], f func(item T)) {
linkedlist.ReverseApply(queue.queueData, f)
}

// Iterate over the queue in the reverse direction and apply a function to each item
// The result of this function is then assigned to the node at each step.
//
// ReverseMap can update the node items by returning the update value.
// If you do not need to modify the queue items, use ReverseApply.
// To accumulate values over the queue, use ReverseFold.
//
// Internally, this method calls linkedlist.ReverseMap
func ReverseMap[T any](queue *LinkedListQueue[T], f func(item T) T) {
linkedlist.ReverseMap(queue.queueData, f)
}

// Iterate over the queue and apply the function f to it.
// The function f also takes the current value of the accumulator.
// The results of f become the new value of the accumulator at each step.
//
// This function returns the final accumulator.
//
// This function is not a method on LinkedListQueue to allow for generic accumulators.
//
// Internally, this method calls linkedlist.ReverseFold
func ReverseFold[T any, G any](queue *LinkedListQueue[T], initialAccumulator G, f func(item T, accumulator G) G) G {
return linkedlist.ReverseFold(queue.queueData, initialAccumulator, f)
}
Loading
Loading