From ca6074e95315976905d4534b890d34b8af3834c8 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Mon, 22 Nov 2021 09:56:05 -0600 Subject: [PATCH] dorking around --- list/list.go | 77 +++++++++++++++++++++++++++++++++++------------ list/list_test.go | 11 ++++--- 2 files changed, 63 insertions(+), 25 deletions(-) diff --git a/list/list.go b/list/list.go index bcb8581..e0ef1f1 100644 --- a/list/list.go +++ b/list/list.go @@ -34,7 +34,7 @@ func (l List[T]) String() string { func Make[T any](vals ...T) List[T] { var l List[T] for i := len(vals)-1; i >= 0; i-- { - l.Prepend(vals[i]) + l.Push(vals[i]) } return l } @@ -44,14 +44,24 @@ func (l List[T]) Empty() bool { return l.head == nil } -// Head returns the first element of the list. If the list is empty, Head -// returns the zero-value for the type T. This is the same thing as Peek() -func (l List[T]) Head() T { - if l.head == nil { - var v T - return v +// At treats the list like an array and gets the value at the i'th position in +// the list (zero-indexed) +func (l List[T]) At(i int) T { + for n, at := l.head, 0; n != nil; n, at = n.next, at+1 { + if at == i { + return n.val + } + } + var v T + return v +} + +// Push adds an element to the front of the list +func (l *List[T]) Push(v T) { + l.head = &node[T]{ + val: v, + next: l.head, } - return l.head.val } // Pop returns the first element of the list and removes it from the list. @@ -66,6 +76,16 @@ func (l *List[T]) Pop() T { return v } +// Head returns the first element of the list. If the list is empty, Head +// returns the zero-value for the type T. This is the same thing as Peek() +func (l List[T]) Head() T { + if l.head == nil { + var v T + return v + } + return l.head.val +} + // Tail returns a list which is the original list without its Head element. // If the original list is an empty list or a list of size 1, Tail is an // empty list. @@ -89,24 +109,14 @@ func (l List[T]) Len() int { return i } -// Prepend adds an element to the front of the list -func (l *List[T]) Prepend(v T) { - l.head = &node[T]{ - val: v, - next: l.head, - } -} - // Map applies the input function f to each element of the list l, returning a // new list containing the values produced by f func (l List[T]) Map(f func(T) T) List[T] { - var mapped List[T] - if l.Empty() { - return mapped + return List[T]{} } - mapped.head = &node[T]{val: f(l.head.val)} + mapped := List[T]{head: &node[T]{val: f(l.head.val)}} last := mapped.head for n := l.head.next; n != nil; n = n.next { last.next = &node[T]{val: f(n.val)} @@ -115,3 +125,30 @@ func (l List[T]) Map(f func(T) T) List[T] { return mapped } + +// Filter applies a predicate function f to each element of the list and +// returns a new list containing the values of the elements that passed the +// predicate +func (l List[T]) Filter(f func(T) bool) List[T] { + if l.Empty() { + return List[T]{} + } + + var passed List[T] + var last *node[T] + for n := l.head; n != nil; n = n.next { + if !f(n.val) { + continue + } + + if passed.Empty() { + passed.head = &node[T]{val: n.val} + last = passed.head + } else { + last.next = &node[T]{val: n.val} + last = last.next + } + } + + return passed +} diff --git a/list/list_test.go b/list/list_test.go index b9e8136..03c1340 100644 --- a/list/list_test.go +++ b/list/list_test.go @@ -28,7 +28,7 @@ func TestEmpty(t *testing.T) { func TestOne(t *testing.T) { var l List[int] - l.Prepend(3) + l.Push(3) if l.Empty() { t.Errorf("list should have 1 element but is empty") @@ -68,7 +68,7 @@ func TestMake(t *testing.T) { t.Errorf("expected a head element of %q but saw %q instead", "bob", l.Head()) } - l.Prepend("alice") + l.Push("alice") if l.Head() != "alice" { t.Errorf("expected a head element of %q but saw %q instead", "alice", l.Head()) } @@ -105,7 +105,8 @@ func eq[T comparable](t *testing.T, expect T, found T) { func TestMap(t *testing.T) { nums := Make(2, 4, 6).Map(mult(5)) - eq(t, 10, nums.Pop()) - eq(t, 20, nums.Pop()) - eq(t, 30, nums.Pop()) + eq(t, 10, nums.At(0)) + eq(t, 20, nums.At(1)) + eq(t, 30, nums.At(2)) + eq(t, 0, nums.At(3)) }