Created the initial version
parent
2146ba3e57
commit
79a3989812
@ -0,0 +1,50 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
type Queue[T any] struct {
|
||||||
|
data []T
|
||||||
|
len int
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an empty queue
|
||||||
|
func NewQueue[T any]() Queue[T] {
|
||||||
|
q := Queue[T]{
|
||||||
|
[]T{},
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue adds an element to the end of the queue.
|
||||||
|
// It appends the given value to the queue's data slice and increments the length of the queue.
|
||||||
|
func (q *Queue[T]) Enqueue(v T) {
|
||||||
|
q.data = append(q.data, v)
|
||||||
|
q.len++
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dequeue removes and returns the element at the front of the queue.
|
||||||
|
// It panics if the queue is empty.
|
||||||
|
func (q *Queue[T]) Dequeue() T {
|
||||||
|
if !q.HasElement() {
|
||||||
|
panic("called Dequeue() on an empty queue")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := q.data[0]
|
||||||
|
var zeroValue T
|
||||||
|
q.data[0] = zeroValue
|
||||||
|
q.data = q.data[1:]
|
||||||
|
|
||||||
|
q.len--
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasElement returns true if the queue has at least one element, otherwise false.
|
||||||
|
func (q *Queue[T]) HasElement() bool {
|
||||||
|
return q.len > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetData returns the data stored in the queue.
|
||||||
|
func (q *Queue[T]) GetData() []T {
|
||||||
|
return q.data
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestQueueDequeue(t *testing.T) {
|
||||||
|
// Create a new queue
|
||||||
|
q := NewQueue[int]()
|
||||||
|
|
||||||
|
// Enqueue some elements
|
||||||
|
q.Enqueue(1)
|
||||||
|
q.Enqueue(2)
|
||||||
|
q.Enqueue(3)
|
||||||
|
|
||||||
|
// Dequeue the elements and check if they match the expected values
|
||||||
|
value := q.Dequeue()
|
||||||
|
if value != 1 {
|
||||||
|
t.Errorf("Expected dequeued value to be 1, but got %v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = q.Dequeue()
|
||||||
|
if value != 2 {
|
||||||
|
t.Errorf("Expected dequeued value to be 2, but got %v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
value = q.Dequeue()
|
||||||
|
if value != 3 {
|
||||||
|
t.Errorf("Expected dequeued value to be 3, but got %v", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to dequeue from an empty queue and expect a panic
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Errorf("Expected Dequeue() to panic, but it didn't")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
q.Dequeue()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestQueueHasElement(t *testing.T) {
|
||||||
|
// Create a new queue
|
||||||
|
q := NewQueue[int]()
|
||||||
|
|
||||||
|
// Check if the queue has elements, expect false
|
||||||
|
if q.HasElement() {
|
||||||
|
t.Errorf("Expected HasElement() to return false, but got true")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enqueue an element
|
||||||
|
q.Enqueue(1)
|
||||||
|
|
||||||
|
// Check if the queue has elements, expect true
|
||||||
|
if !q.HasElement() {
|
||||||
|
t.Errorf("Expected HasElement() to return true, but got false")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dequeue the element
|
||||||
|
q.Dequeue()
|
||||||
|
|
||||||
|
// Check if the queue has elements, expect false
|
||||||
|
if q.HasElement() {
|
||||||
|
t.Errorf("Expected HasElement() to return false, but got true")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 Olivier Abrivard
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package container
|
||||||
|
|
||||||
|
type Stack[T any] struct {
|
||||||
|
data []T
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates an empty stack
|
||||||
|
func NewStack[T any]() Stack[T] {
|
||||||
|
result := Stack[T]{
|
||||||
|
[]T{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Push pushes the value v on top of stack s.
|
||||||
|
func (s *Stack[T]) Push(v T) {
|
||||||
|
s.data = append(s.data, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop removes the value v from the top of stack s and returns it.
|
||||||
|
func (s *Stack[T]) Pop() T {
|
||||||
|
if !s.HasElement() {
|
||||||
|
panic("called Pop() on an empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := s.data[len(s.data)-1]
|
||||||
|
s.data = s.data[0 : len(s.data)-1]
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasElement returns true if the stack s contains at least one element.
|
||||||
|
func (s *Stack[T]) HasElement() bool {
|
||||||
|
return len(s.data) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count returns the number of elements contained in s.
|
||||||
|
func (s *Stack[T]) Count() int {
|
||||||
|
return len(s.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reversed returns a new stack built from stack s, with its elements in reverse order.
|
||||||
|
// s will be emptied by this operation.
|
||||||
|
func (s *Stack[T]) Reversed() Stack[T] {
|
||||||
|
result := Stack[T]{
|
||||||
|
make([]T, len(s.data)),
|
||||||
|
}
|
||||||
|
|
||||||
|
for s.HasElement() {
|
||||||
|
result.Push(s.Pop())
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2022 Olivier Abrivard
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package container
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestEmpty(t *testing.T) {
|
||||||
|
defer func() { _ = recover() }() // turn off the panic
|
||||||
|
|
||||||
|
s := NewStack[int]()
|
||||||
|
s.Pop()
|
||||||
|
|
||||||
|
// Never reaches here if Pop() panics.
|
||||||
|
t.Errorf("Pop() on empty stack should panic")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHasElements(t *testing.T) {
|
||||||
|
s := NewStack[int]()
|
||||||
|
|
||||||
|
if s.HasElement() {
|
||||||
|
t.Errorf("HasElement() should return false for empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Push(1)
|
||||||
|
|
||||||
|
if !s.HasElement() {
|
||||||
|
t.Errorf("HasElement() should return true for non empty stack")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCount(t *testing.T) {
|
||||||
|
s := NewStack[int]()
|
||||||
|
|
||||||
|
if s.Count() != 0 {
|
||||||
|
t.Errorf("Count() should be 0 for empty stack")
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Push(1)
|
||||||
|
|
||||||
|
if s.Count() != 1 {
|
||||||
|
t.Errorf("Count() should be 1 for stack with as single element")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPushPop(t *testing.T) {
|
||||||
|
s1 := NewStack[int]()
|
||||||
|
s1.Push(1)
|
||||||
|
s1.Push(2)
|
||||||
|
s1.Push(3)
|
||||||
|
|
||||||
|
var expectedValues = []int{3, 2, 1}
|
||||||
|
|
||||||
|
for _, expected := range expectedValues {
|
||||||
|
got := s1.Pop()
|
||||||
|
|
||||||
|
if expected != got {
|
||||||
|
t.Errorf("got %d, want %d", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestReversed(t *testing.T) {
|
||||||
|
s1 := NewStack[int]()
|
||||||
|
s1.Push(1)
|
||||||
|
s1.Push(2)
|
||||||
|
s1.Push(3)
|
||||||
|
|
||||||
|
s2 := s1.Reversed()
|
||||||
|
|
||||||
|
if s1.Count() != 0 {
|
||||||
|
t.Errorf("Reversed() should emty the stack it is called upon")
|
||||||
|
}
|
||||||
|
|
||||||
|
var expectedValues = []int{1, 2, 3}
|
||||||
|
|
||||||
|
for _, expected := range expectedValues {
|
||||||
|
got := s2.Pop()
|
||||||
|
|
||||||
|
if expected != got {
|
||||||
|
t.Errorf("got %d, want %d", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
type Vector[T any] []T
|
||||||
|
|
||||||
|
// PushBack adds an element to the end of the vector.
|
||||||
|
// Complexity O(1) + array extesnion
|
||||||
|
func (v *Vector[T]) PushBack(e T) {
|
||||||
|
*v = append(*v, e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopBack removes and returns the last element from the vector.
|
||||||
|
// If the vector is empty, it will panic.
|
||||||
|
// Complexity O(1)
|
||||||
|
func (v *Vector[T]) PopBack() T {
|
||||||
|
if !v.HasElement() {
|
||||||
|
panic("called PopBack() on an empty vector")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := (*v)[len(*v)-1]
|
||||||
|
*v = (*v)[0 : len(*v)-1]
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the length of the vector.
|
||||||
|
// It returns an integer representing the number of elements in the vector.
|
||||||
|
func (v Vector[T]) Len() int {
|
||||||
|
return len(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasElement returns true if the vector v contains at least one element.
|
||||||
|
func (v Vector[T]) HasElement() bool {
|
||||||
|
return v.Len() > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// PushFront adds an element to the front of the vector.
|
||||||
|
// Complexity O(n)
|
||||||
|
func (v *Vector[T]) PushFront(e T) {
|
||||||
|
newVect := make([]T, v.Len()+1)
|
||||||
|
copy(newVect[1:], *v)
|
||||||
|
newVect[0] = e
|
||||||
|
*v = newVect
|
||||||
|
}
|
||||||
|
|
||||||
|
// PopFront removes and returns the element at the front of the vector.
|
||||||
|
// It panics if the vector is empty.
|
||||||
|
// Complexity O(1)
|
||||||
|
func (v *Vector[T]) PopFront() T {
|
||||||
|
if !v.HasElement() {
|
||||||
|
panic("called PopFront() on an empty vector")
|
||||||
|
}
|
||||||
|
|
||||||
|
value := (*v)[0]
|
||||||
|
var zeroValue T
|
||||||
|
(*v)[0] = zeroValue
|
||||||
|
*v = (*v)[1:]
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
@ -0,0 +1,118 @@
|
|||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestVectorPushBack(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3}
|
||||||
|
e := 4
|
||||||
|
|
||||||
|
v.PushBack(e)
|
||||||
|
|
||||||
|
expected := Vector[int]{1, 2, 3, 4}
|
||||||
|
if !reflect.DeepEqual(v, expected) {
|
||||||
|
t.Errorf("PushBack() failed, expected %v, got %v", expected, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Len() != 4 {
|
||||||
|
t.Errorf("expected a length of 4, got %v", v.Len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorPopBack(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3, 4}
|
||||||
|
expectedValue := 4
|
||||||
|
|
||||||
|
value := v.PopBack()
|
||||||
|
|
||||||
|
if value != expectedValue {
|
||||||
|
t.Errorf("PopBack() failed, expected %v, got %v", expectedValue, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedVector := Vector[int]{1, 2, 3}
|
||||||
|
if !reflect.DeepEqual(v, expectedVector) {
|
||||||
|
t.Errorf("PopBack() failed, expected vector %v, got %v", expectedVector, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Len() != 3 {
|
||||||
|
t.Errorf("expected a length of 3, got %v", v.Len())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test panic on empty vector
|
||||||
|
emptyVector := Vector[int]{}
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Errorf("PopBack() did not panic on empty vector")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
emptyVector.PopBack()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorLen(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3}
|
||||||
|
|
||||||
|
expected := 3
|
||||||
|
result := v.Len()
|
||||||
|
|
||||||
|
if result != expected {
|
||||||
|
t.Errorf("Len() failed, expected %d, got %d", expected, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorHasElement(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3}
|
||||||
|
|
||||||
|
hasElement := v.HasElement()
|
||||||
|
|
||||||
|
expected := true
|
||||||
|
if hasElement != expected {
|
||||||
|
t.Errorf("HasElement() failed, expected %v, got %v", expected, hasElement)
|
||||||
|
}
|
||||||
|
|
||||||
|
v = Vector[int]{}
|
||||||
|
|
||||||
|
hasElement = v.HasElement()
|
||||||
|
|
||||||
|
expected = false
|
||||||
|
if hasElement != expected {
|
||||||
|
t.Errorf("HasElement() failed, expected %v, got %v", expected, hasElement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorPushFront(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3}
|
||||||
|
e := 4
|
||||||
|
|
||||||
|
v.PushFront(e)
|
||||||
|
|
||||||
|
expected := Vector[int]{4, 1, 2, 3}
|
||||||
|
if !reflect.DeepEqual(v, expected) {
|
||||||
|
t.Errorf("PushFront() failed, expected %v, got %v", expected, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Len() != 4 {
|
||||||
|
t.Errorf("expected a length of 4, got %v", v.Len())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVectorPopFront(t *testing.T) {
|
||||||
|
v := Vector[int]{1, 2, 3, 4}
|
||||||
|
expectedValue := 1
|
||||||
|
expectedVector := Vector[int]{2, 3, 4}
|
||||||
|
|
||||||
|
value := v.PopFront()
|
||||||
|
|
||||||
|
if value != expectedValue {
|
||||||
|
t.Errorf("PopFront() failed, expected value %v, got %v", expectedValue, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(v, expectedVector) {
|
||||||
|
t.Errorf("PopFront() failed, expected vector %v, got %v", expectedVector, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v.Len() != 3 {
|
||||||
|
t.Errorf("expected a length of 3, got %v", v.Len())
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
package fp
|
||||||
|
|
||||||
|
// Fold applies a function to each element in the slice and accumulates the result.
|
||||||
|
// It takes a slice of type T, an initial value of type A, and a function that combines the accumulator value with each element of the slice.
|
||||||
|
// The function returns the final accumulated value.
|
||||||
|
func Fold[A any, T any](s []T, a A, f func(A, T) A) A {
|
||||||
|
for i := range s {
|
||||||
|
a = f(a, s[i])
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map applies the function f to each element of the slice s and returns a new slice
|
||||||
|
// containing the results.
|
||||||
|
//
|
||||||
|
// The returned slice will contain elements of type M, which is the result
|
||||||
|
// type of the function f.
|
||||||
|
//
|
||||||
|
// Example usage:
|
||||||
|
//
|
||||||
|
// numbers := []int{1, 2, 3, 4, 5}
|
||||||
|
// doubled := Map(numbers, func(n int) int {
|
||||||
|
// return n * 2
|
||||||
|
// })
|
||||||
|
// // doubled is now []int{2, 4, 6, 8, 10}
|
||||||
|
//
|
||||||
|
// names := []string{"Alice", "Bob", "Charlie"}
|
||||||
|
// lengths := Map(names, func(name string) int {
|
||||||
|
// return len(name)
|
||||||
|
// })
|
||||||
|
// // lengths is now []int{5, 3, 7}
|
||||||
|
//
|
||||||
|
// Note: The input slice s is not modified by this function.
|
||||||
|
func Map[T, M any](s []T, f func(T) M) []M {
|
||||||
|
res := []M{}
|
||||||
|
for i := range s {
|
||||||
|
res = append(res, f(s[i]))
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package fp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMap(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []int
|
||||||
|
function func(int) int
|
||||||
|
want []int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "multiply by 2",
|
||||||
|
input: []int{1, 2, 3},
|
||||||
|
function: func(x int) int { return x * 2 },
|
||||||
|
want: []int{2, 4, 6},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "add 1",
|
||||||
|
input: []int{1, 2, 3},
|
||||||
|
function: func(x int) int { return x + 1 },
|
||||||
|
want: []int{2, 3, 4},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "subtract 5",
|
||||||
|
input: []int{10, 15, 20},
|
||||||
|
function: func(x int) int { return x - 5 },
|
||||||
|
want: []int{5, 10, 15},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := Map(tt.input, tt.function)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Map() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFold(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []int
|
||||||
|
accumulator int
|
||||||
|
function func(int, int) int
|
||||||
|
want int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "sum",
|
||||||
|
input: []int{1, 2, 3},
|
||||||
|
accumulator: 0,
|
||||||
|
function: func(a, b int) int { return a + b },
|
||||||
|
want: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "product",
|
||||||
|
input: []int{1, 2, 3},
|
||||||
|
accumulator: 1,
|
||||||
|
function: func(a, b int) int { return a * b },
|
||||||
|
want: 6,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "maximum",
|
||||||
|
input: []int{1, 2, 3},
|
||||||
|
accumulator: 0,
|
||||||
|
function: func(a, b int) int {
|
||||||
|
if a > b {
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
want: 3,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := Fold(tt.input, tt.accumulator, tt.function)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("Fold() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
module gitea.paas.celticinfo.fr/oabrivard/abrolgo
|
||||||
|
|
||||||
|
go 1.21.6
|
||||||
|
|
||||||
|
require golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3
|
||||||
@ -0,0 +1,2 @@
|
|||||||
|
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
|
||||||
|
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||||
@ -0,0 +1,50 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import "math"
|
||||||
|
|
||||||
|
type Point struct {
|
||||||
|
X, Y float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// ShoelaceArea calculates the area of a polygon using the Shoelace formula.
|
||||||
|
// It takes a slice of Point structs representing the vertices of the polygon.
|
||||||
|
// If the number of vertices is less than 3, it returns 0.0 indicating that it is not a valid polygon.
|
||||||
|
func ShoelaceArea(polygon []Point) float64 {
|
||||||
|
if len(polygon) < 3 {
|
||||||
|
return 0.0 // Not a polygon
|
||||||
|
}
|
||||||
|
|
||||||
|
var area float64 = 0.0
|
||||||
|
j := len(polygon) - 1 // The last vertex is the 'previous' one to the first
|
||||||
|
|
||||||
|
for i := 0; i < len(polygon); i++ {
|
||||||
|
area += (polygon[j].X + polygon[i].X) * (polygon[j].Y - polygon[i].Y)
|
||||||
|
j = i // j is previous vertex to i
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0.5 * math.Abs(area)
|
||||||
|
}
|
||||||
|
|
||||||
|
// floodFill performs a flood fill algorithm on the given matrix starting from the specified row and column.
|
||||||
|
// It replaces all occurrences of the previous color with the new color.
|
||||||
|
// The height and width parameters define the dimensions of the matrix.
|
||||||
|
func floodFill(matrix Matrix[int64], row int, col int, prevColor int64, newColor int64, height int, width int) {
|
||||||
|
if row < 0 || row >= height || col < 0 || col >= width {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if matrix[row][col] != prevColor {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if matrix[row][col] == newColor {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix[row][col] = newColor
|
||||||
|
|
||||||
|
floodFill(matrix, row+1, col, prevColor, newColor, height, width)
|
||||||
|
floodFill(matrix, row-1, col, prevColor, newColor, height, width)
|
||||||
|
floodFill(matrix, row, col+1, prevColor, newColor, height, width)
|
||||||
|
floodFill(matrix, row, col-1, prevColor, newColor, height, width)
|
||||||
|
}
|
||||||
@ -0,0 +1,76 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestShoelaceArea(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
polygon []Point
|
||||||
|
want float64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Triangle",
|
||||||
|
polygon: []Point{
|
||||||
|
{X: 0, Y: 0},
|
||||||
|
{X: 0, Y: 4},
|
||||||
|
{X: 3, Y: 0},
|
||||||
|
},
|
||||||
|
want: 6.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Quadrilateral",
|
||||||
|
polygon: []Point{
|
||||||
|
{X: 0, Y: 0},
|
||||||
|
{X: 0, Y: 4},
|
||||||
|
{X: 3, Y: 4},
|
||||||
|
{X: 3, Y: 0},
|
||||||
|
},
|
||||||
|
want: 12.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid Polygon",
|
||||||
|
polygon: []Point{
|
||||||
|
{X: 0, Y: 0},
|
||||||
|
{X: 0, Y: 4},
|
||||||
|
},
|
||||||
|
want: 0.0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := ShoelaceArea(tt.polygon)
|
||||||
|
if got != tt.want {
|
||||||
|
t.Errorf("ShoelaceArea() = %v, want %v", got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFloodFill(t *testing.T) {
|
||||||
|
matrix := Matrix[int64]{
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
}
|
||||||
|
row := 1
|
||||||
|
col := 1
|
||||||
|
prevColor := int64(0)
|
||||||
|
newColor := int64(2)
|
||||||
|
height := 4
|
||||||
|
width := 4
|
||||||
|
|
||||||
|
floodFill(matrix, row, col, prevColor, newColor, height, width)
|
||||||
|
|
||||||
|
expectedMatrix := Matrix[int64]{
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
{1, 2, 2, 1},
|
||||||
|
{1, 2, 2, 1},
|
||||||
|
{1, 1, 1, 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matrix.Equal(expectedMatrix) {
|
||||||
|
t.Errorf("FloodFill() failed, expected matrix: %v, got: %v", expectedMatrix, matrix)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsPrime checks if the given number is prime.
|
||||||
|
// It returns true if the number is prime, and false otherwise.
|
||||||
|
func IsPrime[T constraints.Integer](n T) bool {
|
||||||
|
if n <= 1 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if n <= 3 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if n%2 == 0 || n%3 == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := T(5); i*i <= n; i += 6 {
|
||||||
|
if n%i == 0 || n%(i+2) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// IntPow calculates the power of an integer.
|
||||||
|
// It takes two parameters, x and y, and returns the result of x raised to the power of y.
|
||||||
|
// The type of x and y must be an integer type.
|
||||||
|
func IntPow[T constraints.Integer](x, y T) T {
|
||||||
|
result := T(1)
|
||||||
|
|
||||||
|
for i := T(0); i < y; i++ {
|
||||||
|
result *= x
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pow2 calculates the power of 2 for the given integer value.
|
||||||
|
// It performs a bitwise left shift operation on the number 1 by the value of x.
|
||||||
|
// The result is returned as an integer of the same type as the input.
|
||||||
|
func Pow2[T constraints.Integer](x T) T {
|
||||||
|
return 1 << x
|
||||||
|
}
|
||||||
|
|
||||||
|
// GCD calculates the greatest common divisor (GCD) of two integers.
|
||||||
|
// It uses the Euclidean algorithm to find the GCD.
|
||||||
|
// The function takes two parameters, 'a' and 'b', which represent the integers.
|
||||||
|
// It returns the GCD as the result.
|
||||||
|
func GCD[T constraints.Integer](a, b T) T {
|
||||||
|
for b != 0 {
|
||||||
|
t := b
|
||||||
|
b = a % b
|
||||||
|
a = t
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
// LCM calculates the least common multiple (LCM) of two or more integers.
|
||||||
|
// It takes two integers, a and b, as the first two arguments, and an optional variadic parameter integers for additional integers.
|
||||||
|
// The function uses the GCD (greatest common divisor) function to calculate the LCM.
|
||||||
|
// It returns the LCM as the result.
|
||||||
|
func LCM[T constraints.Integer](a, b T, integers ...T) T {
|
||||||
|
result := a * b / GCD(a, b)
|
||||||
|
|
||||||
|
for i := 0; i < len(integers); i++ {
|
||||||
|
result = LCM(result, integers[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// AbsInt returns the absolute value of an integer.
|
||||||
|
// It takes an integer value x as input and returns the absolute value of x.
|
||||||
|
func AbsInt[T constraints.Integer](x T) T {
|
||||||
|
if x >= 0 {
|
||||||
|
return x
|
||||||
|
} else {
|
||||||
|
return -x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// gaussianElimination performs Gaussian elimination on the given coefficients matrix and right-hand side vector.
|
||||||
|
// It solves a system of linear equations by transforming the coefficients matrix into row-echelon form.
|
||||||
|
// The function takes a square matrix of type Matrix[float64] and a vector of type []float64 as input.
|
||||||
|
// The size of the matrix and the length of the vector should be the same.
|
||||||
|
// The function modifies the coefficients matrix and the right-hand side vector in place.
|
||||||
|
// The solution is stored into the rhs vector.
|
||||||
|
func gaussianElimination(coefficients Matrix[float64], rhs []float64) {
|
||||||
|
size := len(coefficients)
|
||||||
|
for i := 0; i < size; i++ {
|
||||||
|
// Select pivot
|
||||||
|
pivot := coefficients[i][i]
|
||||||
|
// Normalize row i
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
coefficients[i][j] = coefficients[i][j] / pivot
|
||||||
|
}
|
||||||
|
rhs[i] = rhs[i] / pivot
|
||||||
|
// Sweep using row i
|
||||||
|
for k := 0; k < size; k++ {
|
||||||
|
if k != i {
|
||||||
|
factor := coefficients[k][i]
|
||||||
|
for j := 0; j < size; j++ {
|
||||||
|
coefficients[k][j] = coefficients[k][j] - factor*coefficients[i][j]
|
||||||
|
}
|
||||||
|
rhs[k] = rhs[k] - factor*rhs[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,271 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsPrime(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
n int
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
n: 0,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 1,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 2,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 3,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 4,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 5,
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
n: 6,
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
// Add more test cases as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := IsPrime(tt.n)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("IsPrime(%d) = %v, expected %v", tt.n, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIntPow(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
x int
|
||||||
|
y int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
x: 2,
|
||||||
|
y: 3,
|
||||||
|
expected: 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 5,
|
||||||
|
y: 0,
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 10,
|
||||||
|
y: 1,
|
||||||
|
expected: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 3,
|
||||||
|
y: 4,
|
||||||
|
expected: 81,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 2,
|
||||||
|
y: 0,
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 0,
|
||||||
|
y: 5,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: -2,
|
||||||
|
y: 3,
|
||||||
|
expected: -8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := IntPow(tt.x, tt.y)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("IntPow(%d, %d) = %d, expected %d", tt.x, tt.y, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPow2(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
x int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
x: 0,
|
||||||
|
expected: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 1,
|
||||||
|
expected: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 2,
|
||||||
|
expected: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 3,
|
||||||
|
expected: 8,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := Pow2(tt.x)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("Pow2(%d) = %d, expected %d", tt.x, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGCD(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
a: 0,
|
||||||
|
b: 0,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 0,
|
||||||
|
b: 5,
|
||||||
|
expected: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 10,
|
||||||
|
b: 5,
|
||||||
|
expected: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 12,
|
||||||
|
b: 8,
|
||||||
|
expected: 4,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 15,
|
||||||
|
b: 25,
|
||||||
|
expected: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 21,
|
||||||
|
b: 14,
|
||||||
|
expected: 7,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 100,
|
||||||
|
b: 75,
|
||||||
|
expected: 25,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := GCD(tt.a, tt.b)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("GCD(%d, %d) = %d, expected %d", tt.a, tt.b, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestLCM(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
a int
|
||||||
|
b int
|
||||||
|
integers []int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
a: 2,
|
||||||
|
b: 3,
|
||||||
|
integers: []int{4, 5},
|
||||||
|
expected: 60,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 5,
|
||||||
|
b: 7,
|
||||||
|
integers: []int{10, 15},
|
||||||
|
expected: 210,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
a: 12,
|
||||||
|
b: 18,
|
||||||
|
integers: []int{24, 36},
|
||||||
|
expected: 72,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := LCM(tt.a, tt.b, tt.integers...)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("LCM(%d, %d, %v) = %d, expected %d", tt.a, tt.b, tt.integers, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAbsInt(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
x int
|
||||||
|
expected int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
x: 0,
|
||||||
|
expected: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 5,
|
||||||
|
expected: 5,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: -10,
|
||||||
|
expected: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: 100,
|
||||||
|
expected: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: -50,
|
||||||
|
expected: 50,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
result := AbsInt(tt.x)
|
||||||
|
if result != tt.expected {
|
||||||
|
t.Errorf("AbsInt(%d) = %d, expected %d", tt.x, result, tt.expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGaussianElimination(t *testing.T) {
|
||||||
|
coefficients := [][]float64{
|
||||||
|
{2, 1, -1},
|
||||||
|
{-3, -1, 2},
|
||||||
|
{-2, 1, 2},
|
||||||
|
}
|
||||||
|
rhs := []float64{8, -11, -3}
|
||||||
|
|
||||||
|
expected := []float64{2, 3, -1}
|
||||||
|
|
||||||
|
gaussianElimination(coefficients, rhs)
|
||||||
|
|
||||||
|
for i := 0; i < len(rhs); i++ {
|
||||||
|
if rhs[i] != expected[i] {
|
||||||
|
t.Errorf("GaussianElimination failed. Expected %v, got %v", expected, rhs)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
type Matrix[T comparable] [][]T
|
||||||
|
|
||||||
|
// Transpose returns the transpose of the matrix.
|
||||||
|
func (m Matrix[T]) Transpose() Matrix[T] {
|
||||||
|
xl := len(m[0])
|
||||||
|
yl := len(m)
|
||||||
|
result := make([][]T, xl)
|
||||||
|
for i := range result {
|
||||||
|
result[i] = make([]T, yl)
|
||||||
|
}
|
||||||
|
for i := 0; i < xl; i++ {
|
||||||
|
for j := 0; j < yl; j++ {
|
||||||
|
result[i][j] = m[j][i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// RotateClockwise rotates the matrix clockwise by 90 degrees.
|
||||||
|
// It returns a new matrix with the rotated values.
|
||||||
|
func (m Matrix[T]) RotateClockwise() Matrix[T] {
|
||||||
|
xl := len(m[0])
|
||||||
|
yl := len(m)
|
||||||
|
result := make([][]T, xl)
|
||||||
|
for i := range result {
|
||||||
|
result[i] = make([]T, yl)
|
||||||
|
}
|
||||||
|
|
||||||
|
for row := 0; row < yl; row++ {
|
||||||
|
for col := 0; col < xl; col++ {
|
||||||
|
result[col][yl-1-row] = m[row][col]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate creates a duplicate of the matrix.
|
||||||
|
// It returns a new matrix with the same values as the original matrix.
|
||||||
|
func (m Matrix[T]) Duplicate() Matrix[T] {
|
||||||
|
duplicate := make([][]T, len(m))
|
||||||
|
for i := range m {
|
||||||
|
duplicate[i] = make([]T, len(m[i]))
|
||||||
|
copy(duplicate[i], m[i])
|
||||||
|
}
|
||||||
|
return duplicate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equal checks if the current matrix is equal to the given matrix.
|
||||||
|
// It returns true if the matrices are equal, and false otherwise.
|
||||||
|
func (matrix1 Matrix[T]) Equal(matrix2 Matrix[T]) bool {
|
||||||
|
if len(matrix1) != len(matrix2) || len(matrix1[0]) != len(matrix2[0]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(matrix1); i++ {
|
||||||
|
for j := 0; j < len(matrix1[0]); j++ {
|
||||||
|
if matrix1[i][j] != matrix2[i][j] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
@ -0,0 +1,113 @@
|
|||||||
|
package math
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRotateClockwise(t *testing.T) {
|
||||||
|
matrix := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := Matrix[int]{
|
||||||
|
{7, 4, 1},
|
||||||
|
{8, 5, 2},
|
||||||
|
{9, 6, 3},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := matrix.RotateClockwise()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, expected) {
|
||||||
|
t.Errorf("RotateClockwise() = %v, want %v", result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTranspose(t *testing.T) {
|
||||||
|
matrix := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := Matrix[int]{
|
||||||
|
{1, 4, 7},
|
||||||
|
{2, 5, 8},
|
||||||
|
{3, 6, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := matrix.Transpose()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, expected) {
|
||||||
|
t.Errorf("Transpose() = %v, want %v", result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDuplicate(t *testing.T) {
|
||||||
|
matrix := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
result := matrix.Duplicate()
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, expected) {
|
||||||
|
t.Errorf("Duplicate() = %v, want %v", result, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestEqual(t *testing.T) {
|
||||||
|
matrix1 := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix2 := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
if !matrix1.Equal(matrix2) {
|
||||||
|
t.Errorf("Equal() = false, want true")
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix3 := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 9},
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix4 := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
{7, 8, 0},
|
||||||
|
}
|
||||||
|
|
||||||
|
if matrix3.Equal(matrix4) {
|
||||||
|
t.Errorf("Equal() = true, want false")
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix5 := Matrix[int]{
|
||||||
|
{1, 2},
|
||||||
|
{3, 4},
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix6 := Matrix[int]{
|
||||||
|
{1, 2, 3},
|
||||||
|
{4, 5, 6},
|
||||||
|
}
|
||||||
|
|
||||||
|
if matrix5.Equal(matrix6) {
|
||||||
|
t.Errorf("Equal() = true, want false")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,71 @@
|
|||||||
|
// Package parse provides utility functions for parsing and reading data from files.
|
||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/exp/constraints"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReadLines reads all lines from a file specified by fileName and returns them as a slice of strings.
|
||||||
|
func ReadLines(fileName string) []string {
|
||||||
|
result := []string{}
|
||||||
|
file, err := os.Open(fileName)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(file)
|
||||||
|
for scanner.Scan() {
|
||||||
|
result = append(result, scanner.Text())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseIntArray parses a string containing integer values separated by a specified separator and returns a slice of integers.
|
||||||
|
func ParseIntArray[T constraints.Integer](s string, sep string) []T {
|
||||||
|
result := []T{}
|
||||||
|
|
||||||
|
var vals []string
|
||||||
|
if sep == " " {
|
||||||
|
vals = strings.Fields(strings.TrimSpace(s))
|
||||||
|
} else {
|
||||||
|
vals = strings.Split(strings.TrimSpace(s), sep)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, val := range vals {
|
||||||
|
n, e := strconv.ParseInt(strings.TrimSpace(val), 10, 64)
|
||||||
|
if e != nil {
|
||||||
|
log.Fatal(e)
|
||||||
|
}
|
||||||
|
|
||||||
|
result = append(result, T(n))
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// SplitNoBlank splits a string by a specified separator and returns a slice of the non-empty parts.
|
||||||
|
func SplitNoBlank(s string, sep string) []string {
|
||||||
|
splitted_line := strings.Split(s, sep)
|
||||||
|
|
||||||
|
result := []string{}
|
||||||
|
|
||||||
|
for _, part := range splitted_line {
|
||||||
|
if part != "" {
|
||||||
|
result = append(result, part)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
package parse
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestReadLines(t *testing.T) {
|
||||||
|
// Create a temporary file and write some lines to it
|
||||||
|
tmpFile, err := os.CreateTemp("", "testfile")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer os.Remove(tmpFile.Name())
|
||||||
|
|
||||||
|
lines := []string{
|
||||||
|
"Line 1",
|
||||||
|
"Line 2",
|
||||||
|
"Line 3",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
_, err := tmpFile.WriteString(line + "\n")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close the file before reading from it
|
||||||
|
err = tmpFile.Close()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileName := tmpFile.Name()
|
||||||
|
|
||||||
|
// Call the ReadLines function
|
||||||
|
result := ReadLines(fileName)
|
||||||
|
|
||||||
|
// Check if the lines read from file match the expected lines
|
||||||
|
for i, line := range result {
|
||||||
|
if line != lines[i] {
|
||||||
|
t.Errorf("Expected line %d to be '%s', but got '%s'", i+1, lines[i], line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseIntArray(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
separator string
|
||||||
|
want []int64
|
||||||
|
expectFail bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "space separated",
|
||||||
|
input: "1 2 3",
|
||||||
|
separator: " ",
|
||||||
|
want: []int64{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "comma separated",
|
||||||
|
input: "1,2,3",
|
||||||
|
separator: ",",
|
||||||
|
want: []int64{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with leading/trailing spaces",
|
||||||
|
input: " 1, 2, 3 ",
|
||||||
|
separator: ",",
|
||||||
|
want: []int64{1, 2, 3},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
input: "",
|
||||||
|
separator: ",",
|
||||||
|
want: []int64{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := ParseIntArray[int64](tt.input, tt.separator)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("ParseIntArray() = %v, want %v",
|
||||||
|
got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSplitNoBlank(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input string
|
||||||
|
sep string
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "no blank",
|
||||||
|
input: "abc",
|
||||||
|
sep: "",
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "with blanks",
|
||||||
|
input: "a b c",
|
||||||
|
sep: " ",
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "leading/trailing blanks",
|
||||||
|
input: " a b c ",
|
||||||
|
sep: " ",
|
||||||
|
want: []string{"a", "b", "c"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty string",
|
||||||
|
input: "",
|
||||||
|
sep: " ",
|
||||||
|
want: []string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got := SplitNoBlank(tt.input, tt.sep)
|
||||||
|
if !reflect.DeepEqual(got, tt.want) {
|
||||||
|
t.Errorf("SplitNoBlank() = %v, want %v",
|
||||||
|
got, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue