-
-
Save gatspy/568c90c0ee8fcf1c1b8aa5b0c0c58341 to your computer and use it in GitHub Desktop.
Rotate a slice
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package aoc | |
import ( | |
"errors" | |
"reflect" | |
) | |
// rotate rotates the values of a slice by rotate positions, preserving the | |
// rotated values by wrapping them around the slice | |
func rotate(slice interface{}, rotate int) error { | |
// check slice is not nil | |
if slice == nil { | |
return errors.New("non-nil slice interface required") | |
} | |
// get the slice value | |
sliceV := reflect.ValueOf(slice) | |
if sliceV.Kind() != reflect.Slice { | |
return errors.New("slice kind required") | |
} | |
// check slice value is not nil | |
if sliceV.IsNil() { | |
return errors.New("non-nil slice value required") | |
} | |
// slice length | |
sLen := sliceV.Len() | |
// shortcut when empty slice | |
if sLen == 0 { | |
return nil | |
} | |
// limit rotates via modulo | |
rotate %= sLen | |
// Go's % operator returns the remainder and thus can return negative | |
// values. More detail can be found under the `Integer operators` section | |
// here: https://golang.org/ref/spec#Arithmetic_operators | |
if rotate < 0 { | |
rotate += sLen | |
} | |
// shortcut when shift == 0 | |
if rotate == 0 { | |
return nil | |
} | |
// get gcd to determine number of juggles | |
gcd := GCD(rotate, sLen) | |
// do the shifting | |
for i := 0; i < gcd; i++ { | |
// remember the first value | |
temp := reflect.ValueOf(sliceV.Index(i).Interface()) | |
j := i | |
for { | |
k := j + rotate | |
// wrap around slice | |
if k >= sLen { | |
k -= sLen | |
} | |
// end when we're back to where we started | |
if k == i { | |
break | |
} | |
// slice[j] = slice[k] | |
sliceV.Index(j).Set(sliceV.Index(k)) | |
j = k | |
} | |
// slice[j] = slice | |
sliceV.Index(j).Set(temp) | |
// elemJ.Set(temp) | |
} | |
// success | |
return nil | |
} | |
// RotateRight is the analogue to RotateLeft | |
func RotateRight(slice interface{}, by int) error { | |
return rotate(slice, -by) | |
} | |
// RotateLeft is an alias for Rotate | |
func RotateLeft(slice interface{}, by int) error { | |
return rotate(slice, by) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment