mirror of
https://github.com/metabarcoding/obitools4.git
synced 2025-06-29 16:20:46 +00:00
A first prototype for the space of sequences
Former-commit-id: 07dc6ef044b5b6a6fb45dc2acb01dffe71a96195
This commit is contained in:
@ -1,7 +1,18 @@
|
||||
package obiutils
|
||||
|
||||
// Matrix is a generic type representing a matrix.
|
||||
type Matrix[T any] [][]T
|
||||
type Integer interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||
}
|
||||
|
||||
type Float interface {
|
||||
~float32 | ~float64
|
||||
}
|
||||
type Numeric interface {
|
||||
Integer | Float
|
||||
}
|
||||
|
||||
type Vector[T any] []T
|
||||
type Matrix[T any] []Vector[T]
|
||||
|
||||
// Make2DArray generates a 2D array of type T with the specified number of rows and columns.
|
||||
//
|
||||
@ -22,15 +33,20 @@ func Make2DArray[T any](rows, cols int) Matrix[T] {
|
||||
return matrix
|
||||
}
|
||||
|
||||
// Init initializes the Matrix with the given value.
|
||||
//
|
||||
// value: the value to initialize the Matrix elements with.
|
||||
func (matrix *Matrix[T]) Init(value T) {
|
||||
data := (*matrix)[0]
|
||||
data = data[0:cap(data)]
|
||||
for i := range data {
|
||||
data[i] = value
|
||||
func Make2DNumericArray[T Numeric](rows, cols int, zeroed bool) Matrix[T] {
|
||||
matrix := make(Matrix[T], rows)
|
||||
data := make([]T, cols*rows)
|
||||
|
||||
if zeroed {
|
||||
for i := range data {
|
||||
data[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < rows; i++ {
|
||||
matrix[i] = data[i*cols : (i+1)*cols]
|
||||
}
|
||||
return matrix
|
||||
}
|
||||
|
||||
// Row returns the i-th row of the matrix.
|
||||
@ -50,6 +66,19 @@ func (matrix *Matrix[T]) Column(i int) []T {
|
||||
return r
|
||||
}
|
||||
|
||||
// Rows returns the specified rows of the matrix.
|
||||
//
|
||||
// The function takes one or more integer arguments representing the indices of the rows to be returned.
|
||||
// It returns a new matrix containing the specified rows.
|
||||
func (matrix *Matrix[T]) Rows(i ...int) Matrix[T] {
|
||||
res := make([]Vector[T], len(i))
|
||||
|
||||
for j, idx := range i {
|
||||
res[j] = (*matrix)[idx]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Dim returns the dimensions of the Matrix.
|
||||
//
|
||||
// It takes no parameters.
|
||||
|
@ -1,11 +1,17 @@
|
||||
package obiutils
|
||||
|
||||
// InPlaceToLower converts all uppercase letters in the input byte slice to lowercase in place.
|
||||
//
|
||||
// It takes a single parameter:
|
||||
// - data: a byte slice representing the input data
|
||||
//
|
||||
// It returns the modified byte slice.
|
||||
func InPlaceToLower(data []byte) []byte {
|
||||
for i,l := range data {
|
||||
if l >= 'A' && l <='Z' {
|
||||
data[i]|=32
|
||||
for i, l := range data {
|
||||
if l >= 'A' && l <= 'Z' {
|
||||
data[i] |= 32
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
}
|
||||
|
54
pkg/obiutils/cast_interface.go
Normal file
54
pkg/obiutils/cast_interface.go
Normal file
@ -0,0 +1,54 @@
|
||||
package obiutils
|
||||
|
||||
// CastableToInt checks if the given input can be casted to an integer.
|
||||
//
|
||||
// i: the value to check for castability.
|
||||
// bool: true if the value can be casted to an integer, false otherwise.
|
||||
func CastableToInt(i interface{}) bool {
|
||||
switch i.(type) {
|
||||
case int,
|
||||
int8, int16, int32, int64,
|
||||
float32, float64,
|
||||
uint8, uint16, uint32, uint64:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// InterfaceToBool converts an interface value to a boolean.
|
||||
//
|
||||
// It takes an interface{} as a parameter and returns a boolean value and an error.
|
||||
func InterfaceToBool(i interface{}) (val bool, err error) {
|
||||
|
||||
err = nil
|
||||
val = false
|
||||
|
||||
switch t := i.(type) {
|
||||
case int:
|
||||
val = t != 0
|
||||
case int8:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int16:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int64:
|
||||
val = t != 0 // standardizes across systems
|
||||
case float32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case float64:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint8:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint16:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint64:
|
||||
val = t != 0 // standardizes across systems
|
||||
default:
|
||||
err = &NotABoolean{"value attribute cannot be casted to a boolean"}
|
||||
}
|
||||
return
|
||||
}
|
@ -196,6 +196,69 @@ func InterfaceToFloat64Map(i interface{}) (val map[string]float64, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// InterfaceToFloat64Slice converts an interface{} to a []float64 slice.
|
||||
//
|
||||
// It takes an interface{} parameter and returns a slice of float64 values and an error.
|
||||
func InterfaceToFloat64Slice(i interface{}) ([]float64, error) {
|
||||
switch i := i.(type) {
|
||||
case []float64:
|
||||
return i, nil
|
||||
case []interface{}:
|
||||
val := make([]float64, len(i))
|
||||
for k, v := range i {
|
||||
if x, err := InterfaceToFloat64(v); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
val[k] = x
|
||||
}
|
||||
}
|
||||
return val, nil
|
||||
case []int:
|
||||
val := make([]float64, len(i))
|
||||
for k, v := range i {
|
||||
val[k] = float64(v)
|
||||
}
|
||||
return val, nil
|
||||
default:
|
||||
return nil, &NotAMapFloat64{"value attribute cannot be casted to a []float64"}
|
||||
}
|
||||
}
|
||||
|
||||
// InterfaceToIntSlice converts an interface{} to a []int slice.
|
||||
//
|
||||
// It takes an interface{} parameter and returns a slice of int values and an error.
|
||||
func InterfaceToIntSlice(i interface{}) ([]int, error) {
|
||||
|
||||
switch i := i.(type) {
|
||||
case []int:
|
||||
return i, nil
|
||||
case []interface{}:
|
||||
val := make([]int, len(i))
|
||||
for k, v := range i {
|
||||
if x, err := InterfaceToInt(v); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
val[k] = x
|
||||
}
|
||||
}
|
||||
return val, nil
|
||||
case []float64:
|
||||
val := make([]int, len(i))
|
||||
for k, v := range i {
|
||||
val[k] = int(v + 0.5)
|
||||
}
|
||||
return val, nil
|
||||
case Vector[float64]:
|
||||
val := make([]int, len(i))
|
||||
for k, v := range i {
|
||||
val[k] = int(v + 0.5)
|
||||
}
|
||||
return val, nil
|
||||
default:
|
||||
return nil, &NotAMapInt{"value attribute cannot be casted to a []int"}
|
||||
}
|
||||
}
|
||||
|
||||
// NotABoolean defines a new type of Error : "NotABoolean"
|
||||
type NotABoolean struct {
|
||||
message string
|
||||
@ -208,56 +271,6 @@ func (m *NotABoolean) Error() string {
|
||||
return m.message
|
||||
}
|
||||
|
||||
// It converts an interface{} to a bool, and returns an error if the interface{} cannot be converted
|
||||
// to a bool
|
||||
func InterfaceToBool(i interface{}) (val bool, err error) {
|
||||
|
||||
err = nil
|
||||
val = false
|
||||
|
||||
switch t := i.(type) {
|
||||
case int:
|
||||
val = t != 0
|
||||
case int8:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int16:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case int64:
|
||||
val = t != 0 // standardizes across systems
|
||||
case float32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case float64:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint8:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint16:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint32:
|
||||
val = t != 0 // standardizes across systems
|
||||
case uint64:
|
||||
val = t != 0 // standardizes across systems
|
||||
default:
|
||||
err = &NotABoolean{"value attribute cannot be casted to a boolean"}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// If the interface{} can be cast to an int, return true.
|
||||
func CastableToInt(i interface{}) bool {
|
||||
|
||||
switch i.(type) {
|
||||
case int,
|
||||
int8, int16, int32, int64,
|
||||
float32, float64,
|
||||
uint8, uint16, uint32, uint64:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// > It copies the contents of the `src` map into the `dest` map, but if the value is a map, slice, or
|
||||
// array, it makes a deep copy of it
|
||||
func MustFillMap(dest, src map[string]interface{}) {
|
||||
@ -270,8 +283,15 @@ func MustFillMap(dest, src map[string]interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadLines reads the lines from a file specified by the given path.
|
||||
//
|
||||
// Read a whole file into the memory and store it as array of lines
|
||||
// It reads a file line by line, and returns a slice of strings, one for each line
|
||||
//
|
||||
// It takes a single parameter:
|
||||
// - path: a string representing the path of the file to read.
|
||||
//
|
||||
// It returns a slice of strings containing the lines read from the file, and an error if any occurred.
|
||||
func ReadLines(path string) (lines []string, err error) {
|
||||
var (
|
||||
file *os.File
|
||||
@ -301,6 +321,14 @@ func ReadLines(path string) (lines []string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// AtomicCounter creates and returns a function that generates a unique integer value each time it is called.
|
||||
//
|
||||
// The function takes an optional initial value as a parameter. If an initial value is provided, the generated
|
||||
// integers will start from that value. If no initial value is provided, the generated integers will start from 0.
|
||||
//
|
||||
// The function is thread safe.
|
||||
//
|
||||
// The function returns a closure that can be called to retrieve the next integer in the sequence.
|
||||
func AtomicCounter(initial ...int) func() int {
|
||||
counterMutex := sync.Mutex{}
|
||||
counter := 0
|
||||
@ -320,12 +348,16 @@ func AtomicCounter(initial ...int) func() int {
|
||||
return nextCounter
|
||||
}
|
||||
|
||||
// Marshal is a UTF-8 friendly marshaler. Go's json.Marshal is not UTF-8
|
||||
// JsonMarshal marshals an interface into JSON format.
|
||||
//
|
||||
// JsonMarshal is a UTF-8 friendly marshaler. Go's json.Marshal is not UTF-8
|
||||
// friendly because it replaces the valid UTF-8 and JSON characters "&". "<",
|
||||
// ">" with the "slash u" unicode escaped forms (e.g. \u0026). It preemptively
|
||||
// escapes for HTML friendliness. Where text may include any of these
|
||||
// characters, json.Marshal should not be used. Playground of Go breaking a
|
||||
// title: https://play.golang.org/p/o2hiX0c62oN
|
||||
//
|
||||
// It takes an interface as a parameter and returns a byte slice and an error.
|
||||
func JsonMarshal(i interface{}) ([]byte, error) {
|
||||
buffer := &bytes.Buffer{}
|
||||
encoder := json.NewEncoder(buffer)
|
||||
@ -334,22 +366,45 @@ func JsonMarshal(i interface{}) ([]byte, error) {
|
||||
return bytes.TrimRight(buffer.Bytes(), "\n"), err
|
||||
}
|
||||
|
||||
// IsAMap checks if the given value is a map.
|
||||
//
|
||||
// value: the value to be checked.
|
||||
// returns: a boolean indicating if the value is a map.
|
||||
func IsAMap(value interface{}) bool {
|
||||
return reflect.TypeOf(value).Kind() == reflect.Map
|
||||
}
|
||||
|
||||
// IsAnArray checks if the given value is an array.
|
||||
//
|
||||
// value: The value to be checked.
|
||||
// Returns: true if the value is an array, false otherwise.
|
||||
func IsAnArray(value interface{}) bool {
|
||||
return reflect.TypeOf(value).Kind() == reflect.Array
|
||||
}
|
||||
|
||||
// IsASlice determines if the given value is a slice.
|
||||
//
|
||||
// value: the value to check.
|
||||
// bool: true if the value is a slice, false otherwise.
|
||||
func IsASlice(value interface{}) bool {
|
||||
return reflect.TypeOf(value).Kind() == reflect.Slice
|
||||
}
|
||||
|
||||
// HasLength checks if the given value has a length.
|
||||
//
|
||||
// value: The value to be checked.
|
||||
// bool: Returns true if the value has a length, false otherwise.
|
||||
func HasLength(value interface{}) bool {
|
||||
_, ok := value.(interface{ Len() int })
|
||||
return IsAMap(value) || IsAnArray(value) || IsASlice(value) || ok
|
||||
}
|
||||
|
||||
// Len returns the length of the given value.
|
||||
//
|
||||
// It accepts a single parameter:
|
||||
// - value: an interface{} that represents the value whose length is to be determined.
|
||||
//
|
||||
// It returns an int, which represents the length of the value.
|
||||
func Len(value interface{}) int {
|
||||
l := 1
|
||||
|
||||
|
@ -65,6 +65,10 @@ func (r Ranker[_]) Len() int { return len(r.r) }
|
||||
func (r Ranker[T]) Less(i, j int) bool { return r.x.Less(r.r[i], r.r[j]) }
|
||||
func (r Ranker[_]) Swap(i, j int) { r.r[i], r.r[j] = r.r[j], r.r[i] }
|
||||
|
||||
// Order sorts the given data using the provided sort.Interface and returns the sorted indices.
|
||||
//
|
||||
// data: The data to be sorted.
|
||||
// Returns: A slice of integers representing the sorted indices.
|
||||
func Order[T sort.Interface](data T) []int {
|
||||
ldata := data.Len()
|
||||
if ldata == 0 {
|
||||
|
@ -1,5 +1,13 @@
|
||||
package obiutils
|
||||
|
||||
// Contains checks if the given element is present in the given array.
|
||||
//
|
||||
// Parameters:
|
||||
// - arr: The array to search in.
|
||||
// - x: The element to search for.
|
||||
//
|
||||
// Return type:
|
||||
// - bool: Returns true if the element is found, false otherwise.
|
||||
func Contains[T comparable](arr []T, x T) bool {
|
||||
for _, v := range arr {
|
||||
if v == x {
|
||||
@ -9,6 +17,14 @@ func Contains[T comparable](arr []T, x T) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// LookFor searches for the first occurrence of a given element in an array and returns its index.
|
||||
//
|
||||
// Parameters:
|
||||
// - arr: the array to be searched
|
||||
// - x: the element to search for
|
||||
//
|
||||
// Return:
|
||||
// - int: the index of the first occurrence of the element in the array, or -1 if not found
|
||||
func LookFor[T comparable](arr []T, x T) int {
|
||||
for i, v := range arr {
|
||||
if v == x {
|
||||
@ -18,19 +34,36 @@ func LookFor[T comparable](arr []T, x T) int {
|
||||
return -1
|
||||
}
|
||||
|
||||
// RemoveIndex removes an element at a specified index from a slice.
|
||||
//
|
||||
// Parameters:
|
||||
// - s: The slice from which the element will be removed.
|
||||
// - index: The index of the element to be removed.
|
||||
//
|
||||
// Returns:
|
||||
// A new slice with the element removed.
|
||||
func RemoveIndex[T comparable](s []T, index int) []T {
|
||||
return append(s[:index], s[index+1:]...)
|
||||
}
|
||||
|
||||
// Reverse reverses the elements of a slice.
|
||||
//
|
||||
// The function takes a slice `s` and a boolean `inplace` parameter. If `inplace`
|
||||
// is `true`, the function modifies the input slice directly. If `inplace` is
|
||||
// `false`, the function creates a new slice `c` and copies the elements of `s`
|
||||
// into `c`. The function then reverses the elements of `s` in-place or `c`
|
||||
// depending on the `inplace` parameter.
|
||||
//
|
||||
// The function returns the reversed slice.
|
||||
func Reverse[S ~[]E, E any](s S, inplace bool) S {
|
||||
if !inplace {
|
||||
c := make([]E,len(s))
|
||||
copy(c,s)
|
||||
c := make([]E, len(s))
|
||||
copy(c, s)
|
||||
s = c
|
||||
}
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
Reference in New Issue
Block a user