Semver sort
February 12, 2023
Problem
- given input array of string contains release version that must follow
x.y.z
form. x.y.z
must be integer with positive values- sort by latest release
Solution
See in playground https://go.dev/play/p/_nFWNUOcDCu (opens in a new tab).
The process is straigtforward
- Parse string into semver struct
- Sort using custom slice and implement required sorting interface
Len
,Swap
andLess
, refers to https://pkg.go.dev/sort#example-package (opens in a new tab) - Revert back to array of string where version string follows
x.y.z
format
package mainimport ( "fmt" "sort" "strconv" "strings")// Semver represents a semantic version in the format x.y.ztype Semver struct { Major int Minor int Patch int}func (s Semver) ToString() string { return fmt.Sprintf("%d.%d.%d", s.Major, s.Minor, s.Patch)}// NewSemver returns a new Semver instance with the specified major, minor, and patch values.func NewSemver(major int, minor int, patch int) Semver { return Semver{ Major: major, Minor: minor, Patch: patch, }}// ParseSemver takes a string representation of a semantic version in the format x.y.z and returns a new Semver instance.func ParseSemver(version string) (Semver, error) { parts := strings.Split(version, ".") if len(parts) != 3 { return Semver{}, fmt.Errorf("invalid version format: %s", version) } major, minor, patch := 0, 0, 0 var err error if major, err = strconv.Atoi(parts[0]); err != nil || major < 0 { return Semver{}, fmt.Errorf("invalid major version: %s", parts[0]) } if minor, err = strconv.Atoi(parts[1]); err != nil || minor < 0 { return Semver{}, fmt.Errorf("invalid minor version: %s", parts[1]) } if patch, err = strconv.Atoi(parts[2]); err != nil || patch < 0 { return Semver{}, fmt.Errorf("invalid patch version: %s", parts[2]) } return NewSemver(major, minor, patch), nil}// Versions is a slice of Semver instancestype Versions []Semverfunc (v Versions) Len() int { return len(v)}func (v Versions) Less(i, j int) bool { if v[i].Major != v[j].Major { return v[i].Major < v[j].Major } if v[i].Minor != v[j].Minor { return v[i].Minor < v[j].Minor } return v[i].Patch < v[j].Patch}func (v Versions) Swap(i, j int) { v[i], v[j] = v[j], v[i]}func solution(input []string) []string { var versions Versions for _, v := range input { semver, err := ParseSemver(v) if err == nil { versions = append(versions, semver) } } sort.Sort(sort.Reverse(versions)) result := []string{} for _, v := range versions { result = append(result, v.ToString()) } return result}func main() { input := []string{"1.0.0", "2.0.0", "0.1.0", "3.0.0", "invalid", "1.2.3", "1.2.3-rc", "1.-1.2"} result := solution(input) fmt.Println(result)}