diff --git a/pkg/csdlinkList/csdlinkList.go b/pkg/csdlinkList/csdlinkList.go index a2d05dc..c38db40 100644 --- a/pkg/csdlinkList/csdlinkList.go +++ b/pkg/csdlinkList/csdlinkList.go @@ -217,6 +217,41 @@ func (cs *CSDLinkList[T]) ForEach(f func(*T)) { cs.l.ForEach(f) } +// ForFrom traverses the doubly linked list starting from the given index and applies the given function to each node. +func (cs *CSDLinkList[T]) ForFrom(index int, f func(*T)) { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.l.ForFrom(index, f) +} + +// ForReverseFrom traverses the doubly linked list in reverse order starting from the given index and applies the given function to each node. +func (cs *CSDLinkList[T]) ForReverseFrom(index int, f func(*T)) { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.l.ForReverseFrom(index, f) +} + +// ForEachReverse traverses the doubly linked list in reverse order and applies the given function to each node. +func (cs *CSDLinkList[T]) ForEachReverse(f func(*T)) { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.l.ForEachReverse(f) +} + +// ForRange traverses the doubly linked list in the given range and applies the given function to each node. +func (cs *CSDLinkList[T]) ForRange(start, end int, f func(*T)) { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.l.ForRange(start, end, f) +} + +// ForReverseRange traverses the doubly linked list in reverse order in the given range and applies the given function to each node. +func (cs *CSDLinkList[T]) ForReverseRange(start, end int, f func(*T)) { + cs.mu.Lock() + defer cs.mu.Unlock() + cs.l.ForReverseRange(start, end, f) +} + // Any returns true if the given function returns true for any node in the doubly linked list. func (cs *CSDLinkList[T]) Any(f func(T) bool) bool { cs.mu.Lock() @@ -259,6 +294,20 @@ func (cs *CSDLinkList[T]) Map(f func(T) T) *CSDLinkList[T] { return &CSDLinkList[T]{l: cs.l.Map(f)} } +// MapFrom returns a new doubly linked list containing the result of applying the given function to each node starting from the given index. +func (cs *CSDLinkList[T]) MapFrom(index int, f func(T) T) *CSDLinkList[T] { + cs.mu.Lock() + defer cs.mu.Unlock() + return &CSDLinkList[T]{l: cs.l.MapFrom(index, f)} +} + +// MapRange returns a new doubly linked list containing the result of applying the given function to each node in the given range. +func (cs *CSDLinkList[T]) MapRange(start, end int, f func(T) T) *CSDLinkList[T] { + cs.mu.Lock() + defer cs.mu.Unlock() + return &CSDLinkList[T]{l: cs.l.MapRange(start, end, f)} +} + // Reduce reduces the doubly linked list to a single value using the given function. func (cs *CSDLinkList[T]) Reduce(f func(T, T) T) T { cs.mu.Lock() diff --git a/pkg/csdlinkList/csdlinkList_test.go b/pkg/csdlinkList/csdlinkList_test.go index 925e6f3..d9a2297 100644 --- a/pkg/csdlinkList/csdlinkList_test.go +++ b/pkg/csdlinkList/csdlinkList_test.go @@ -188,6 +188,22 @@ func TestCSDLinkListToSliceFrom(t *testing.T) { }) } +func TestCSDLinkListToSliceReverseFromIndex(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + for i := 0; i < 1000; i++ { + cs.Append(i) + } + runConcurrent(t, 1000, func() { + test := cs.ToSliceReverseFromIndex(50) + if len(test) != 950 { + t.Fatalf("expected size 50, got %d", len(test)) + } + if test[0] != 949 { + t.Fatalf("expected first element to be 950, got %d", test[0]) + } + }) +} + func TestCSDLinkListFind(t *testing.T) { cs := csdlinkList.NewCSDLinkList[int]() cs.Append(1) @@ -281,6 +297,58 @@ func TestCSDLinkListForEach(t *testing.T) { }) } +func TestCSDLinkListForEachReverse(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + for i := 1000; i > 0; i-- { + cs.Append(i) + } + runConcurrent(t, 1000, func() { + cs.ForEachReverse(func(item *int) { + *item = *item + 1 + }) + }) +} + +func TestCSDLinkListForRange(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.ForRange(0, 1, func(item *int) { + *item = *item + 1 + }) + }) +} + +func TestCSDLinkListForFrom(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.ForFrom(0, func(item *int) { + *item = *item + 1 + }) + }) +} + +func TestCSDLinkListForReverseFrom(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.ForReverseFrom(0, func(item *int) { + *item = *item + 1 + }) + }) +} + +func TestCSDLinkListForReverseRange(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.ForReverseRange(0, 1, func(item *int) { + *item = *item + 1 + }) + }) +} + func TestCSDLinkListAny(t *testing.T) { cs := csdlinkList.NewCSDLinkList[int]() for i := 0; i < 1000; i++ { @@ -349,6 +417,26 @@ func TestCSDLinkListMap(t *testing.T) { }) } +func TestCSDLinkListMapFrom(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.MapFrom(0, func(item int) int { + return item * 2 + }) + }) +} + +func TestCSDLinkListMapRange(t *testing.T) { + cs := csdlinkList.NewCSDLinkList[int]() + cs.Append(1) + runConcurrent(t, 1000, func() { + cs.MapRange(0, 1, func(item int) int { + return item * 2 + }) + }) +} + func TestCSDLinkListReduce(t *testing.T) { cs := csdlinkList.NewCSDLinkList[int]() for i := 0; i < 1000; i++ { diff --git a/pkg/dlinkList/dlinkList.go b/pkg/dlinkList/dlinkList.go index 3029d6d..e83d977 100644 --- a/pkg/dlinkList/dlinkList.go +++ b/pkg/dlinkList/dlinkList.go @@ -442,6 +442,10 @@ func (l *DLinkList[T]) Contains(value T) bool { // ForEach traverses the doubly linked list and applies the given function to each node func (l *DLinkList[T]) ForEach(f func(*T)) { + if l.IsEmpty() { + return + } + current := l.Head for current != nil { f(¤t.Value) @@ -449,6 +453,115 @@ func (l *DLinkList[T]) ForEach(f func(*T)) { } } +// ForFrom traverses the doubly linked list starting from the given index and applies the given function to each node +func (l *DLinkList[T]) ForFrom(index int, f func(*T)) { + if index < 0 { + return + } + + if l.IsEmpty() { + return + } + + current, err := l.GetAt(index) + if err != nil { + return + } + + for current != nil { + f(¤t.Value) + current = current.Next + if current == nil { + break + } + } +} + +// ForEachReverse traverses the doubly linked list in reverse order and applies the given function to each node +func (l *DLinkList[T]) ForEachReverse(f func(*T)) { + if l.IsEmpty() { + return + } + + current := l.Tail + for current != nil { + f(¤t.Value) + current = current.Prev + } +} + +// ForReverseFrom traverses the doubly linked list in reverse order starting from the given index and applies the given function to each node +func (l *DLinkList[T]) ForReverseFrom(index int, f func(*T)) { + if index < 0 { + return + } + + if l.IsEmpty() { + return + } + + current, err := l.GetAt((l.Size() - 1) - index) + if err != nil { + return + } + + for current != nil { + f(¤t.Value) + current = current.Prev + if current == nil { + break + } + } +} + +// ForRange traverses the doubly linked list from the start index to the end index and applies the given function to each node +func (l *DLinkList[T]) ForRange(start, end int, f func(*T)) { + if start < 0 || end < 0 || start > end { + return + } + + if l.IsEmpty() { + return + } + + current, err := l.GetAt(start) + if err != nil { + return + } + + for i := start; i <= end; i++ { + f(¤t.Value) + current = current.Next + if current == nil { + break + } + } +} + +// ForReverseRange traverses the doubly linked list in reverse order from the start index to the end index and applies the given function to each node +func (l *DLinkList[T]) ForReverseRange(start, end int, f func(*T)) { + if start < 0 || end < 0 || start > end { + return + } + + if l.IsEmpty() { + return + } + + current, err := l.GetAt((l.Size() - 1) - start) + if err != nil { + return + } + + for i := start; i <= end; i++ { + f(¤t.Value) + current = current.Prev + if current == nil { + break + } + } +} + // Any returns true if the given function returns true for any node in the doubly linked list func (l *DLinkList[T]) Any(f func(T) bool) bool { current := l.Head @@ -533,6 +646,62 @@ func (l *DLinkList[T]) Map(f func(T) T) *DLinkList[T] { return result } +// MapFrom returns a new doubly linked list containing the result of applying the given function to each node starting from the given index +func (l *DLinkList[T]) MapFrom(index int, f func(T) T) *DLinkList[T] { + result := NewDLinkList[T]() + + if index < 0 { + return result + } + + if l.IsEmpty() { + return result + } + + current, err := l.GetAt(index) + if err != nil { + return result + } + + for current != nil { + result.Append(f(current.Value)) + current = current.Next + if current == nil { + break + } + } + + return result +} + +// MapRange returns a new doubly linked list containing the result of applying the given function to each node in the range [start, end) +func (l *DLinkList[T]) MapRange(start, end int, f func(T) T) *DLinkList[T] { + result := NewDLinkList[T]() + + if start < 0 || end < 0 || start > end { + return result + } + + if l.IsEmpty() { + return result + } + + current, err := l.GetAt(start) + if err != nil { + return result + } + + for i := start; i <= end; i++ { + result.Append(f(current.Value)) + current = current.Next + if current == nil { + break + } + } + + return result +} + // Reduce reduces the doubly linked list to a single value using the given function func (l *DLinkList[T]) Reduce(f func(T, T) T) T { if l.IsEmpty() {