- Published on
Semver sort
- Authors
- Name
- Moch Lutfi
- @kaptenupi
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.
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 - Revert back to array of string where version string follows
x.y.z
format
_95package main_95_95import (_95 "fmt"_95 "sort"_95 "strconv"_95 "strings"_95)_95_95// Semver represents a semantic version in the format x.y.z_95type Semver struct {_95 Major int_95 Minor int_95 Patch int_95}_95_95func (s Semver) ToString() string {_95 return fmt.Sprintf("%d.%d.%d", s.Major, s.Minor, s.Patch)_95}_95_95// NewSemver returns a new Semver instance with the specified major, minor, and patch values._95func NewSemver(major int, minor int, patch int) Semver {_95 return Semver{_95 Major: major,_95 Minor: minor,_95 Patch: patch,_95 }_95}_95_95// ParseSemver takes a string representation of a semantic version in the format x.y.z and returns a new Semver instance._95func ParseSemver(version string) (Semver, error) {_95 parts := strings.Split(version, ".")_95 if len(parts) != 3 {_95 return Semver{}, fmt.Errorf("invalid version format: %s", version)_95 }_95_95 major, minor, patch := 0, 0, 0_95 var err error_95 if major, err = strconv.Atoi(parts[0]); err != nil || major < 0 {_95 return Semver{}, fmt.Errorf("invalid major version: %s", parts[0])_95 }_95 if minor, err = strconv.Atoi(parts[1]); err != nil || minor < 0 {_95 return Semver{}, fmt.Errorf("invalid minor version: %s", parts[1])_95 }_95 if patch, err = strconv.Atoi(parts[2]); err != nil || patch < 0 {_95 return Semver{}, fmt.Errorf("invalid patch version: %s", parts[2])_95 }_95_95 return NewSemver(major, minor, patch), nil_95}_95_95// Versions is a slice of Semver instances_95type Versions []Semver_95_95func (v Versions) Len() int {_95 return len(v)_95}_95_95func (v Versions) Less(i, j int) bool {_95 if v[i].Major != v[j].Major {_95 return v[i].Major < v[j].Major_95 }_95 if v[i].Minor != v[j].Minor {_95 return v[i].Minor < v[j].Minor_95 }_95 return v[i].Patch < v[j].Patch_95}_95_95func (v Versions) Swap(i, j int) {_95 v[i], v[j] = v[j], v[i]_95}_95_95func solution(input []string) []string {_95 var versions Versions_95 for _, v := range input {_95 semver, err := ParseSemver(v)_95 if err == nil {_95 versions = append(versions, semver)_95 }_95 }_95_95 sort.Sort(sort.Reverse(versions))_95 result := []string{}_95 for _, v := range versions {_95 result = append(result, v.ToString())_95 }_95 return result_95}_95_95func main() {_95 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"}_95_95 result := solution(input)_95 fmt.Println(result)_95}