Skip to content

Commit

Permalink
Merge pull request #5 from geniussportsgroup/develop
Browse files Browse the repository at this point in the history
Added rotation and reverse methods
  • Loading branch information
lrleon committed Mar 24, 2021
2 parents 3ebb6d2 + f5c949f commit cfa6cb5
Show file tree
Hide file tree
Showing 3 changed files with 254 additions and 7 deletions.
133 changes: 127 additions & 6 deletions functional.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package FunctionalLib

import (
"fmt"
Seq "github.com/geniussportsgroup/Slist"
)

Expand All @@ -20,14 +21,17 @@ type Sequence interface {
CreateIterator() interface{}
}

// A pair of interfaces. Returned by Zip
type Pair struct {
Item1, Item2 interface{}
}

// Represent a tuple
type Tuple struct {
l *[]interface{}
}

// Return a new tuple with the received elements
func NewTuple(items ...interface{}) *Tuple {

s := make([]interface{}, 0, len(items))
Expand All @@ -38,25 +42,29 @@ func NewTuple(items ...interface{}) *Tuple {
return &tuple
}

// Build a tuple for storing n elements
func BuildTuple(n int) *Tuple {
s := make([]interface{}, n, n)
return &Tuple{l: &s}
}

// Set the i-th element of the tuple with item
func (tuple *Tuple) Set(i int, item interface{}) {
(*tuple.l)[i] = item
}

func (tuple *Tuple) Traverse(f func(interface{}) bool) bool {
// Traverse the tuple an executes operation on each element
func (tuple *Tuple) Traverse(operation func(interface{}) bool) bool {
ptr := tuple.l
for i := 0; i < len(*tuple.l); i++ {
if !f((*ptr)[i]) {
if !operation((*ptr)[i]) {
return false
}
}
return true
}

// Append one or more elements to the tuple
func (tuple *Tuple) Append(item interface{}, items ...interface{}) interface{} {
*tuple.l = append(*tuple.l, item)
for _, i := range items {
Expand All @@ -65,16 +73,19 @@ func (tuple *Tuple) Append(item interface{}, items ...interface{}) interface{} {
return tuple
}

// Return the length of the tuple
func (tuple *Tuple) Size() int {
return len(*tuple.l)
}

// Swap in O(1) two tuples
func (tuple *Tuple) Swap(other interface{}) interface{} {
otherTuple := other.(*Tuple)
tuple.l, otherTuple.l = otherTuple.l, tuple.l
return tuple
}

// Return true if the tuple is empty
func (tuple *Tuple) IsEmpty() bool {
return tuple.Size() == 0
}
Expand All @@ -84,39 +95,149 @@ type TupleIterator struct {
pos int
}

// Return an iterator to the tuple compliant with the interface Sequence
func (tuple *Tuple) CreateIterator() interface{} {
return &TupleIterator{
tuple: tuple,
pos: 0,
}
}

// Return an new iterator to the tuple
func NewTupleIterator(tuple Tuple) *TupleIterator {
return tuple.CreateIterator().(*TupleIterator)
}

// Return true if the iterator is on a element
func (it *TupleIterator) HasCurr() bool {
return it.pos < len(*it.tuple.l)
}

// Return the element of which the iterator is positioned
func (it *TupleIterator) GetCurr() interface{} {
return (*it.tuple.l)[it.pos]
}

func (tuple *Tuple) Nth(i int) interface{} {
return (*tuple.l)[i]
}

// Advance the iterator to the next item of the tuple
func (it *TupleIterator) Next() interface{} {
it.pos++
return it
}

// Reset the iterator to the first element
func (it *TupleIterator) ResetFirst() interface{} {
it.pos = 0
return it
}

// Return the n-th element of the tuple
func (tuple *Tuple) Nth(i int) interface{} {
return (*tuple.l)[i]
}

// ReverseInPlace the subsequence between i and k
func (tuple *Tuple) ReverseInterval(i, j int) *Tuple {

sz := tuple.Size()
if i < 0 || i >= sz {
panic(fmt.Sprintf("Invalid value for i = %d", i))
}

if j < 0 || j >= sz {
panic(fmt.Sprintf("Invalid value for j = %d", j))
}

if i > j {
panic(fmt.Sprintf("i = %d is greater than j = %d", i, j))
}

for i <= j {
(*tuple.l)[i], (*tuple.l)[j] = (*tuple.l)[j], (*tuple.l)[i]
i++
j--
}

return tuple
}

// Reverse the tuple in place
func (tuple *Tuple) ReverseInPlace() *Tuple {
return tuple.ReverseInterval(0, tuple.Size()-1)
}

// Return a reversed copy of tuple
func (tuple *Tuple) Reverse() *Tuple {
return tuple.clone().ReverseInterval(0, tuple.Size()-1)
}

func (tuple *Tuple) validateRotateIndexes(i, j, n int) {
if i > j {
panic(fmt.Sprintf("%d < %d", i, j))
}

if i < 0 || i >= tuple.Size() || j < 0 || j >= tuple.Size() {
panic(fmt.Sprintf("Invalid i = %d or j = %d", i, j))
}

n = n % tuple.Size()
l := j - i
if n > l {
panic(fmt.Sprintf("n = %d greater than interval size = %d", n, l))
}
}

// Rotate in place to right n positions the subsequence in [i, j]
func (tuple *Tuple) RotateIntervalRightInPlace(i, j, n int) *Tuple {

tuple.validateRotateIndexes(i, j, n)

tuple.ReverseInterval(i, i+n-1)
tuple.ReverseInterval(i+n, j)
tuple.ReverseInterval(i, j)

return tuple
}

// Rotate in place to right n positions the subsequence in [i, j]
func (tuple *Tuple) RotateIntervalLeftInPlace(i, j, n int) *Tuple {

tuple.validateRotateIndexes(i, j, n)

tuple.ReverseInterval(j-n+1, j)
tuple.ReverseInterval(i, j-n)
tuple.ReverseInterval(i, j)

return tuple
}

// Rotate in place the sequence n positions to right
func (tuple *Tuple) RotateRightInPlace(n int) *Tuple {
tuple.RotateIntervalRightInPlace(0, tuple.Size()-1, n)

return tuple
}

// Rotate in place the sequence n positions to left
func (tuple *Tuple) RotateLeftInPlace(n int) *Tuple {
tuple.RotateIntervalLeftInPlace(0, tuple.Size()-1, n)

return tuple
}

// Return a new tuple copy of tuple rotate n position to right
func (tuple *Tuple) RotateRight(n int) *Tuple {
return tuple.clone().RotateRightInPlace(n)
}

// Return a new tuple copy of tuple rotate n position to left
func (tuple *Tuple) RotateLeft(n int) *Tuple {
return tuple.clone().RotateLeftInPlace(n)
}

func (tuple *Tuple) clone() *Tuple {
return NewTuple(*tuple.l...)
}

// Execute operation receiving every item of the sequence. Return seq
func ForEach(seq Sequence, operation func(interface{})) interface{} {

Expand Down
126 changes: 126 additions & 0 deletions functional_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package FunctionalLib

import (
"fmt"
Seq "github.com/geniussportsgroup/Slist"
Set "github.com/geniussportsgroup/treaps"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -300,3 +301,128 @@ func TestTUnzip(t *testing.T) {
return i1 == i2
}))
}

func TestTuple_ReverseInterval(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

tuple.ReverseInterval(1, 5)
assert.Equal(t, tuple.Nth(1).(int), 5)
assert.Equal(t, tuple.Nth(2).(int), 4)
assert.Equal(t, tuple.Nth(3).(int), 3)
assert.Equal(t, tuple.Nth(4).(int), 2)
assert.Equal(t, tuple.Nth(5).(int), 1)

assert.Panics(t, func() {
tuple.ReverseInterval(5, 3)
})

assert.Panics(t, func() {
tuple.ReverseInterval(-1, 3)
})

assert.Panics(t, func() {
tuple.ReverseInterval(1, -3)
})

assert.Panics(t, func() {
tuple.ReverseInterval(10, 13)
})

assert.Panics(t, func() {
tuple.ReverseInterval(5, 13)
})

assert.Panics(t, func() {
tuple.ReverseInterval(5, 3)
})
}

func TestTuple_Reverse(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5)
tuple.ReverseInPlace()
for i := 0; i < tuple.Size(); i++ {
assert.Equal(t, tuple.Nth(i), tuple.Size()-i-1)
}

tuple.ReverseInPlace()
for i := 0; i < tuple.Size(); i++ {
assert.Equal(t, tuple.Nth(i), i)
}
}

func TestTuple_RotateIntervalRightInPlace(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplep := tuple.clone()
ForEach(tuple, func(i interface{}) {
fmt.Print(i, " ")
})
fmt.Println()

tuple.RotateIntervalRightInPlace(2, 5, 2)
ForEach(tuple, func(i interface{}) {
fmt.Print(i, " ")
})
fmt.Println()

assert.True(t, All(Zip(tuple.RotateIntervalLeftInPlace(2, 5, 2), tuplep),
func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))
}

func TestTuple_RotateIntervalLeftInPlace(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplep := tuple.clone()
ForEach(tuple, func(i interface{}) {
fmt.Print(i, " ")
})
fmt.Println()

tuple.RotateIntervalLeftInPlace(2, 5, 2)
ForEach(tuple, func(i interface{}) {
fmt.Print(i, " ")
})
fmt.Println()

assert.True(t, All(Zip(tuple.RotateIntervalRightInPlace(2, 5, 2), tuplep),
func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))
}

func TestTuple_clone(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
assert.True(t, All(Zip(tuple, tuple.clone()), func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))
}

func TestTuple_RotationsInPlace(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
tuplep := tuple.clone()

tuple.RotateRightInPlace(3)

assert.True(t, All(Zip(tuple.RotateLeftInPlace(3), tuplep), func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))
}

func TestTuple_Rotations(t *testing.T) {

tuple := NewTuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)

assert.True(t, All(Zip(tuple, tuple.RotateRight(3).RotateLeft(3)), func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))

assert.True(t, All(Zip(tuple, tuple.RotateLeft(3).RotateRight(3)), func(pair interface{}) bool {
return pair.(Pair).Item1.(int) == pair.(Pair).Item2.(int)
}))
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/geniussportsgroup/FunctionalLib
go 1.15

require (
github.com/geniussportsgroup/Slist v1.0.5
github.com/geniussportsgroup/Slist v1.0.6
github.com/geniussportsgroup/treaps v1.1.8
github.com/stretchr/testify v1.7.0
)

0 comments on commit cfa6cb5

Please sign in to comment.