mirror of
https://github.com/metabarcoding/obitools4.git
synced 2026-06-24 01:31:00 +00:00
feat: add which_max and which_min to retrieve extreme element indices
Implement reflection-based WhichMax and WhichMin to dynamically find the index or key of the maximum/minimum element in slices, arrays, or maps. Functions validate orderability, handle empty collections, and dispatch via reflect.Kind. Expose as which_max and which_min GVal functions, with float64 type assertions for compatibility and preserved error handling.
This commit is contained in:
@@ -141,6 +141,20 @@ var OBILang = gval.NewLanguage(
|
|||||||
gval.Function("max", func(args ...interface{}) (interface{}, error) {
|
gval.Function("max", func(args ...interface{}) (interface{}, error) {
|
||||||
return obiutils.Max(args[0])
|
return obiutils.Max(args[0])
|
||||||
}),
|
}),
|
||||||
|
gval.Function("which_max", func(args ...interface{}) (interface{}, error) {
|
||||||
|
result, err := obiutils.WhichMax(args[0])
|
||||||
|
if idx, ok := result.(int); ok {
|
||||||
|
return float64(idx), nil
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}),
|
||||||
|
gval.Function("which_min", func(args ...interface{}) (interface{}, error) {
|
||||||
|
result, err := obiutils.WhichMin(args[0])
|
||||||
|
if idx, ok := result.(int); ok {
|
||||||
|
return float64(idx), nil
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}),
|
||||||
|
|
||||||
gval.Function("filtermin", func(args ...interface{}) (interface{}, error) {
|
gval.Function("filtermin", func(args ...interface{}) (interface{}, error) {
|
||||||
return obiutils.FilterMin(args[0], args[1])
|
return obiutils.FilterMin(args[0], args[1])
|
||||||
|
|||||||
@@ -365,6 +365,116 @@ func filterMaxFromIterable(v reflect.Value, maximum interface{}) (interface{}, e
|
|||||||
return result.Interface(), nil
|
return result.Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// whichMaxFromIterable returns the index of the maximum element in a slice/array.
|
||||||
|
func whichMaxFromIterable(v reflect.Value) (int, error) {
|
||||||
|
var best reflect.Value
|
||||||
|
bestIdx := 0
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
elem := unwrapInterface(v.Index(i))
|
||||||
|
if !isOrderedKind(elem.Kind()) {
|
||||||
|
return 0, fmt.Errorf("unsupported element type: %s", elem.Kind())
|
||||||
|
}
|
||||||
|
if i == 0 || greater(elem, best) {
|
||||||
|
best = elem
|
||||||
|
bestIdx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestIdx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// whichMinFromIterable returns the index of the minimum element in a slice/array.
|
||||||
|
func whichMinFromIterable(v reflect.Value) (int, error) {
|
||||||
|
var minVal reflect.Value
|
||||||
|
minIdx := 0
|
||||||
|
for i := 0; i < v.Len(); i++ {
|
||||||
|
elem := unwrapInterface(v.Index(i))
|
||||||
|
if !isOrderedKind(elem.Kind()) {
|
||||||
|
return 0, fmt.Errorf("unsupported element type: %s", elem.Kind())
|
||||||
|
}
|
||||||
|
if i == 0 || less(elem, minVal) {
|
||||||
|
minVal = elem
|
||||||
|
minIdx = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minIdx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// whichMaxFromMap returns the key associated with the maximum value in a map.
|
||||||
|
func whichMaxFromMap(v reflect.Value) (interface{}, error) {
|
||||||
|
var best reflect.Value
|
||||||
|
var bestKey reflect.Value
|
||||||
|
first := true
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
elem := unwrapInterface(v.MapIndex(key))
|
||||||
|
if !isOrderedKind(elem.Kind()) {
|
||||||
|
return nil, fmt.Errorf("unsupported element type: %s", elem.Kind())
|
||||||
|
}
|
||||||
|
if first || greater(elem, best) {
|
||||||
|
best = elem
|
||||||
|
bestKey = key
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bestKey.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// whichMinFromMap returns the key associated with the minimum value in a map.
|
||||||
|
func whichMinFromMap(v reflect.Value) (interface{}, error) {
|
||||||
|
var minVal reflect.Value
|
||||||
|
var minKey reflect.Value
|
||||||
|
first := true
|
||||||
|
for _, key := range v.MapKeys() {
|
||||||
|
elem := unwrapInterface(v.MapIndex(key))
|
||||||
|
if !isOrderedKind(elem.Kind()) {
|
||||||
|
return nil, fmt.Errorf("unsupported element type: %s", elem.Kind())
|
||||||
|
}
|
||||||
|
if first || less(elem, minVal) {
|
||||||
|
minVal = elem
|
||||||
|
minKey = key
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return minKey.Interface(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhichMax returns the key (for a map) or index (for a slice/array) of the maximum value.
|
||||||
|
func WhichMax(data interface{}) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(data)
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
if v.Len() == 0 {
|
||||||
|
return nil, errors.New("empty slice or array")
|
||||||
|
}
|
||||||
|
return whichMaxFromIterable(v)
|
||||||
|
case reflect.Map:
|
||||||
|
if v.Len() == 0 {
|
||||||
|
return nil, errors.New("empty map")
|
||||||
|
}
|
||||||
|
return whichMaxFromMap(v)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported type: %s", v.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// WhichMin returns the key (for a map) or index (for a slice/array) of the minimum value.
|
||||||
|
func WhichMin(data interface{}) (interface{}, error) {
|
||||||
|
v := reflect.ValueOf(data)
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Slice, reflect.Array:
|
||||||
|
if v.Len() == 0 {
|
||||||
|
return nil, errors.New("empty slice or array")
|
||||||
|
}
|
||||||
|
return whichMinFromIterable(v)
|
||||||
|
case reflect.Map:
|
||||||
|
if v.Len() == 0 {
|
||||||
|
return nil, errors.New("empty map")
|
||||||
|
}
|
||||||
|
return whichMinFromMap(v)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unsupported type: %s", v.Kind())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func filterMinFromMap(v reflect.Value, minimum interface{}) (interface{}, error) {
|
func filterMinFromMap(v reflect.Value, minimum interface{}) (interface{}, error) {
|
||||||
minVal := reflect.ValueOf(minimum)
|
minVal := reflect.ValueOf(minimum)
|
||||||
result := reflect.MakeMap(v.Type())
|
result := reflect.MakeMap(v.Type())
|
||||||
|
|||||||
Reference in New Issue
Block a user