dunno how to feeeeeeeeeel
commit
82696bb29a
@ -0,0 +1,117 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type node[T any] struct {
|
||||
val T
|
||||
next *node[T]
|
||||
}
|
||||
|
||||
// List[T] is a singly-linked list of T
|
||||
type List[T any] struct {
|
||||
head *node[T]
|
||||
}
|
||||
|
||||
func (l List[T]) String() string {
|
||||
var buf strings.Builder
|
||||
|
||||
buf.WriteRune('[')
|
||||
for n := l.head; n != nil; n = n.next {
|
||||
fmt.Fprintf(&buf, "%v", n.val)
|
||||
if n.next != nil {
|
||||
buf.WriteString(", ")
|
||||
}
|
||||
}
|
||||
buf.WriteRune(']')
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// Make creates a list of T with a set of provided values. It's called Make
|
||||
// instead of New because it performs O(n) allocations, where n == len(vals)
|
||||
func Make[T any](vals ...T) List[T] {
|
||||
var l List[T]
|
||||
for i := len(vals)-1; i >= 0; i-- {
|
||||
l.Prepend(vals[i])
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Empty is true for empty lists
|
||||
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
|
||||
}
|
||||
return l.head.val
|
||||
}
|
||||
|
||||
// Pop returns the first element of the list and removes it from the list.
|
||||
func (l *List[T]) Pop() T {
|
||||
if l.Empty() {
|
||||
var v T
|
||||
return v
|
||||
}
|
||||
|
||||
v := l.head.val
|
||||
l.head = l.head.next
|
||||
return v
|
||||
}
|
||||
|
||||
// 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.
|
||||
func (l List[T]) Tail() List[T] {
|
||||
if l.head == nil || l.head.next == nil {
|
||||
return List[T]{}
|
||||
}
|
||||
return List[T]{head: l.head.next}
|
||||
}
|
||||
|
||||
// Len is the length of the list
|
||||
func (l List[T]) Len() int {
|
||||
if l.head == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
i := 0
|
||||
for n := l.head; n != nil; n = n.next {
|
||||
i++
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
mapped.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)}
|
||||
last = last.next
|
||||
}
|
||||
|
||||
return mapped
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEmpty(t *testing.T) {
|
||||
var l List[int]
|
||||
|
||||
if !l.Empty() {
|
||||
t.Errorf("new list is not empty, but should be")
|
||||
}
|
||||
|
||||
if l.Head() != 0 {
|
||||
t.Errorf("expect head of list to be zero-value for that type but saw %d instead of 0 for int", l.Head())
|
||||
}
|
||||
|
||||
tail := l.Tail()
|
||||
if !tail.Empty() {
|
||||
t.Errorf("empty list should have empty tail but saw %v instead", tail)
|
||||
}
|
||||
|
||||
if l.Len() != 0 {
|
||||
t.Errorf("empty list should have a length of 0 but has %d instead", l.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestOne(t *testing.T) {
|
||||
var l List[int]
|
||||
|
||||
l.Prepend(3)
|
||||
|
||||
if l.Empty() {
|
||||
t.Errorf("list should have 1 element but is empty")
|
||||
}
|
||||
|
||||
if l.Head() != 3 {
|
||||
t.Errorf("list's head element should be 3 but saw %d instead", l.Head())
|
||||
}
|
||||
|
||||
if l.Len() != 1 {
|
||||
t.Errorf("expected a list of size 1 but saw %d instead", l.Len())
|
||||
}
|
||||
}
|
||||
|
||||
func TestMake(t *testing.T) {
|
||||
t.Run("empty", func(t *testing.T) {
|
||||
// This doesn't work because the type parameter T cannot be inferred:
|
||||
// Make[]()
|
||||
|
||||
// You have to provide T in the case of an empty list
|
||||
l := Make[int]()
|
||||
if !l.Empty() {
|
||||
t.Errorf("make with no params should create empty list but gave %v instead", l)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("some strings", func(t *testing.T) {
|
||||
// The type parameter T can be inferred based on the arguments passed
|
||||
// in
|
||||
l := Make("bob", "carol", "dave")
|
||||
|
||||
if l.Len() != 3 {
|
||||
t.Errorf("expected length of 3 but saw %d instead", l.Len())
|
||||
}
|
||||
|
||||
if l.Head() != "bob" {
|
||||
t.Errorf("expected a head element of %q but saw %q instead", "bob", l.Head())
|
||||
}
|
||||
|
||||
l.Prepend("alice")
|
||||
if l.Head() != "alice" {
|
||||
t.Errorf("expected a head element of %q but saw %q instead", "alice", l.Head())
|
||||
}
|
||||
if l.Len() != 4 {
|
||||
t.Errorf("expected length of 4 but saw %d instead", l.Len())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("mixed element types", func(t *testing.T) {
|
||||
l := Make[any]("alice", 3, "carol")
|
||||
|
||||
if l.Len() != 3 {
|
||||
t.Errorf("expected length of 3 but saw %d instead", l.Len())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func mult[T wholeNumber](x T) func(T) T {
|
||||
return func(y T) T {
|
||||
return x * y
|
||||
}
|
||||
}
|
||||
|
||||
type wholeNumber interface {
|
||||
~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uint |
|
||||
~int8 | ~int16 | ~int32 | ~int64 | int
|
||||
}
|
||||
|
||||
func eq[T comparable](t *testing.T, expect T, found T) {
|
||||
if found != expect {
|
||||
t.Errorf("expected %v, found %v", expect, found)
|
||||
}
|
||||
}
|
||||
|
||||
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())
|
||||
}
|
Loading…
Reference in New Issue