Skip to content
257 changes: 257 additions & 0 deletions indexofmax.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
package funk

import "strings"

// IndexOfMaxInt returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// This function implements the argMax functionality requested in GitHub issue #139.
// It accepts []int.
// It returns int.
func IndexOfMaxInt(arr []int) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue int
var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxInt8 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []int8.
// It returns int.
func IndexOfMaxInt8(arr []int8) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue int8
var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxInt16 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []int16.
// It returns int.
func IndexOfMaxInt16(arr []int16) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue int16
var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxInt32 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []int32.
// It returns int.
func IndexOfMaxInt32(arr []int32) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue int32

var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxInt64 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []int64.
// It returns int.
func IndexOfMaxInt64(arr []int64) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue int64

var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxFloat32 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []float32.
// It returns int.
func IndexOfMaxFloat32(arr []float32) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue float32

var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxFloat64 returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []float64.
// It returns int.
func IndexOfMaxFloat64(arr []float64) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue float64
var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if item > maxValue {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// IndexOfMaxString returns the index of the maximum element in an array/slice.
// If there are duplicate occurrences of max element, only return the first one.
// It accepts []string.
// It returns int.
func IndexOfMaxString(arr []string) int {
if len(arr) == 0 {
panic("arg is an empty array/slice")
}

var maxValue string
var maxIndex int

for idx := 0; idx < len(arr); idx++ {
item := arr[idx]
if idx == 0 {
maxValue = item
maxIndex = 0

continue
}

if compareStringsIndexOfMax(maxValue, item) == item {
maxValue = item
maxIndex = idx
}
}

return maxIndex
}

// compareStringsIndexOfMax uses the strings.Compare method to compare two strings, and returns the greater one.
func compareStringsIndexOfMax(maxValue, current string) string {
r := strings.Compare(strings.ToLower(maxValue), strings.ToLower(current))
if r >= 0 {
return maxValue
}

return current
}
72 changes: 72 additions & 0 deletions indexofmax_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package funk

import (
"testing"

"github.com/stretchr/testify/assert"
)

// TestIndexOfMaxIssue139Example tests the exact example provided in GitHub issue #139.
func TestIndexOfMaxIssue139Example(t *testing.T) {
t.Parallel()

nums := []int64{8, 3, 4, 44, 0}
result := IndexOfMaxInt64(nums)
assert.Equal(t, 3, result, "Should return index 3 for the example in issue #139")
assert.Equal(t, int64(44), nums[result], "The element at returned index should be 44")
}

func TestIndexOfMaxWithArrayNumericInput(t *testing.T) {
t.Parallel()

// Test Data
data1 := []int{8, 3, 4, 44, 0}
data1dup := []int{44, 3, 4, 44, 0} // duplicate max at beginning
emptyData := []int{}

// Calls
result1 := IndexOfMaxInt(data1)
result1dup := IndexOfMaxInt(data1dup)

// Assertions
assert.Equal(t, 3, result1, "It should return the index of max value in array")
assert.Equal(t, 0, result1dup, "It should return the first index of duplicate max value")
assert.Panics(t, func() { IndexOfMaxInt(emptyData) }, "It should panic")
}

func TestIndexOfMaxWithArrayFloatInput(t *testing.T) {
t.Parallel()

// Test Data
data1 := []float64{2, 38.3, 4, 4.4, 4}
data1dup := []float64{38.3, 2, 4, 38.3, 4} // duplicate max at beginning
emptyData := []float64{}

// Calls
result1 := IndexOfMaxFloat64(data1)
result1dup := IndexOfMaxFloat64(data1dup)

// Assertions
assert.Equal(t, 1, result1, "It should return the index of max value in array")
assert.Equal(t, 0, result1dup, "It should return the first index of duplicate max value")
assert.Panics(t, func() { IndexOfMaxFloat64(emptyData) }, "It should panic")
}

func TestIndexOfMaxSingleElement(t *testing.T) {
t.Parallel()

// Test Data with single elements
data1 := []int{42}
data2 := []float64{3.14}
data3 := []string{"hello"}

// Calls
result1 := IndexOfMaxInt(data1)
result2 := IndexOfMaxFloat64(data2)
result3 := IndexOfMaxString(data3)

// Assertions
assert.Equal(t, 0, result1, "Single element should return index 0")
assert.Equal(t, 0, result2, "Single element should return index 0")
assert.Equal(t, 0, result3, "Single element should return index 0")
}
Loading