The challenge

Given a slice of positive integers, return the value with the most digits. If two or more values share the highest digit count, return the first one in the slice.

Examples:

findLongest([]int{1, 10, 100})     // → 100
findLongest([]int{9000, 8, 800})   // → 9000
findLongest([]int{8, 900, 500})    // → 900

This Codewars-style puzzle is asked in Go interviews and screens for understanding of slices, ties, and avoiding allocations.

Solution 1: count digits with integer division

The most idiomatic Go version — no strconv allocation:

package main

func digitCount(n int) int {
    if n == 0 {
        return 1
    }
    count := 0
    for n > 0 {
        n /= 10
        count++
    }
    return count
}

func findLongest(nums []int) int {
    longest := nums[0]
    longestDigits := digitCount(nums[0])

    for i := 1; i < len(nums); i++ {
        d := digitCount(nums[i])
        if d > longestDigits {
            longest = nums[i]
            longestDigits = d
        }
    }
    return longest
}

Why this works: Each n /= 10 strips one digit. The strict > comparison preserves the first match on ties. No heap allocation, no float math.

Solution 2: strconv.Itoa shortcut

If readability beats micro-optimisation:

package main

import "strconv"

func findLongest(nums []int) int {
    longest := nums[0]
    longestDigits := len(strconv.Itoa(nums[0]))

    for i := 1; i < len(nums); i++ {
        d := len(strconv.Itoa(nums[i]))
        if d > longestDigits {
            longest = nums[i]
            longestDigits = d
        }
    }
    return longest
}

Trade-off: allocates a string for each element. Fine for thousands of inputs, slow for millions.

Solution 3: slices.MaxFunc with a stable wrapper (Go 1.21+)

If you want the standard-library helper but need first-match-wins behaviour:

package main

import (
    "slices"
    "strconv"
)

func findLongest(nums []int) int {
    return slices.MaxFunc(nums, func(a, b int) int {
        da, db := len(strconv.Itoa(a)), len(strconv.Itoa(b))
        if db > da {
            return -1 // b wins ONLY if strictly greater
        }
        return 1 // otherwise a wins (first occurrence stays)
    })
}

Why this works: slices.MaxFunc returns the maximum according to the comparator. By returning 1 (a wins) on equal counts, we make sure the earlier element is treated as “greater” — preserving first-match semantics.

Complexity

Solution Time Space
Integer division O(n × d) O(1) extra
strconv.Itoa O(n × d) O(n × d) GC
slices.MaxFunc O(n × d) O(n × d) GC

Where n = len(nums) and d is the average digit count. For Go’s 64-bit ints d ≤ 19.

Edge cases

  • Single element: findLongest([]int{42}) returns 42.
  • Zero inside the slice: digitCount(0) returns 1, matching how humans count digits.
  • Empty slice: all three solutions panic on nums[0] — add if len(nums) == 0 { return 0 } if your callers might pass empty.

Test cases

package main

import "testing"

func TestFindLongest(t *testing.T) {
    cases := []struct {
        in   []int
        want int
    }{
        {[]int{1, 10, 100}, 100},
        {[]int{9000, 8, 800}, 9000},
        {[]int{8, 900, 500}, 900},
        {[]int{3, 40000, 100}, 40000},
        {[]int{1, 200, 100000}, 100000},
        {[]int{42}, 42},
    }
    for _, c := range cases {
        if got := findLongest(c.in); got != c.want {
            t.Errorf("findLongest(%v) = %d, want %d", c.in, got, c.want)
        }
    }
}