Cookies management by TermsFeed Cookie Consent

🖖 Calculate Median in Go using Generics

numbers math generics generics-intro

To find the median of a slice in Go, you need to write a custom function that sorts the input slice and gets the middle element. If the slice size is even, the function calculates the mean (average) of the two middle values. In the following examples, we will show two versions of this function: a regular one that takes a float64 slice as input, and a Generics version, that can work for any numeric type.

If you are not already familiar with the basics of Generics in Go, check out our series of articles: Introduction to Go Generics by example.

Also, check out our tutorial on how to calculate the arithmetic mean in Go.

Calculate median in Go - example

To calculate the median in the classic way, we need to create a new median() function and start with the input data copy. Calculating the median requires sorting the data first, so to avoid modifying the original slice order, we need a copy of the input slice. We then take the middle value from this sorted slice. This is our median. If the data size is an odd number, the middle element will be the value at index <slice_length>/2. If the data size is even, it will be the arithmetic average of the two middle elements.

package main

import (
    "fmt"
    "sort"
)

func median(data []float64) float64 {
    dataCopy := make([]float64, len(data))
    copy(dataCopy, data)

    sort.Float64s(dataCopy)

    var median float64
    l := len(dataCopy)
    if l == 0 {
        return 0
    } else if l%2 == 0 {
        median = (dataCopy[l/2-1] + dataCopy[l/2]) / 2
    } else {
        median = dataCopy[l/2]
    }

    return median
}

func main() {
    fmt.Println(median([]float64{1, 3, 2}))
    fmt.Println(median([]float64{1}))
    fmt.Println(median([]float64{3, 3, 3, 3, 2, 22, 2, 2, 2, 2, 1, 1, 1, 1, 1, 111}))
}

Output:

2
1
2

Use Generics to calculate median

Since the release of Generics in Go 1.18, it is possible to write the median() function that works for a slice of any numeric type. Simply define the Number constraint which is a union of constraints.Float and constraints.Integer to limit the input types to numeric. For more details, see the example on how to calculate the arithmetic mean using Generics, where we also used the Number constraint.

Another difference is that, in the generic version, we use the slices.Sort() function from the new /x/exp/slices package to sort the slice. It allows for generic sorting of slices of any type.

package main

import (
    "fmt"

    "golang.org/x/exp/constraints"
    "golang.org/x/exp/slices"
)

type Number interface {
    constraints.Float | constraints.Integer
}

func median[T Number](data []T) float64 {
    dataCopy := make([]T, len(data))
    copy(dataCopy, data)

    slices.Sort(dataCopy)

    var median float64
    l := len(dataCopy)
    if l == 0 {
        return 0
    } else if l%2 == 0 {
        median = float64((dataCopy[l/2-1] + dataCopy[l/2]) / 2.0)
    } else {
        median = float64(dataCopy[l/2])
    }

    return median
}

func main() {
    fmt.Println(median([]float64{1, 3, 2}))
    fmt.Println(median([]int{1}))
    fmt.Println(median([]int32{3, 3, 3, 3, 2, 22, 2, 2, 2, 2, 1, 1, 1, 1, 1, 111}))
}

The result is a function that works seamlessly for a slice of type int, int64, float64, etc., without having to copy code, or create special versions for each type.

Output:

2
1
2

Thank you for being on our site 😊. If you like our tutorials and examples, please consider supporting us with a cup of coffee and we'll turn it into more great Go examples.

Have a great day!

Buy Me A Coffee

🤏 Calculate arithmetic mean in Go using Generics

Learn how to calculate mean for a slice of any numeric type
numbers math generics generics-intro

🫘 Count the occurrences of an element in a slice in Go

Learn how to count elements in a slice that meet certain conditions
introduction generics generics-intro

🧊 Cube root in Go

shorts numbers math