sorthelper

package module
v0.1.5 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 11, 2023 License: BSD-3-Clause Imports: 3 Imported by: 0

README

sorthelper

sorthelper is a Go library which provides convenience for sorting slices and user-defined collections.

Installation

go get github.com/weiwenchen2022/sorthelper

Reference

godoc or http://godoc.org/github.com/weiwenchen2022/sorthelper

Documentation

Overview

Package sorthelper provides convenience for sorting slices and user-defined collections.

Example
package main

import (
	"fmt"
	"sort"

	"github.com/weiwenchen2022/sorthelper"
)

type Person struct {
	Name string
	Age  int
}

func (p Person) String() string {
	return fmt.Sprintf("%s: %d", p.Name, p.Age)
}

// ByAge implements sort.Interface for []Person based on
// the Age field, by providing Less and using the Len and
// Swap methods of the embedded slice value.
type ByAge struct{ sorthelper.Slice[Person] }

func (a ByAge) Less(i, j int) bool { return a.Slice[i].Age < a.Slice[j].Age }

func main() {
	people := []Person{
		{"Bob", 31},
		{"John", 42},
		{"Michael", 17},
		{"Jenny", 26},
	}
	fmt.Println(people)

	// There are two ways to sort a slice. First, one can define
	// a set of methods for the slice type, as with ByAge, and
	// call sort.Sort. In this first example we use that technique.
	sort.Sort(ByAge{people})
	fmt.Println(people)

	// The other way is to use sort.Slice with a custom Less
	// function, which can be provided as a closure. In this
	// case no methods are needed. (And if they exist, they
	// are ignored.) Here we re-sort in reverse order: compare
	// the closure with ByAge.Less.
	sort.Slice(people, func(i, j int) bool {
		return people[i].Age > people[j].Age
	})
	fmt.Println(people)

}
Output:

[Bob: 31 John: 42 Michael: 17 Jenny: 26]
[Michael: 17 Jenny: 26 Bob: 31 John: 42]
[John: 42 Bob: 31 Jenny: 26 Michael: 17]
Example (SortKeys)

ExampleSortKeys demonstrates sorting a struct type using Sorter with programmable sort criteria.

package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

// A couple of type definitions to make the units clear.
type earthMass float64
type au float64

// A Planet defines the properties of a solar system object.
type Planet struct {
	name     string
	mass     earthMass
	distance au
}

var planets = []Planet{
	{"Mercury", 0.055, 0.4},
	{"Venus", 0.815, 0.7},
	{"Earth", 1.0, 1.0},
	{"Mars", 0.107, 1.5},
}

// ExampleSortKeys demonstrates sorting a struct type using Sorter with programmable sort criteria.
func main() {
	// Closures that order the Planet structure.
	name := func(p1, p2 *Planet) bool {
		return p1.name < p2.name
	}
	mass := func(p1, p2 *Planet) bool {
		return p1.mass < p2.mass
	}
	distance := func(p1, p2 *Planet) bool {
		return p1.distance < p2.distance
	}
	decreasingDistance := func(p1, p2 *Planet) bool {
		return distance(p2, p1)
	}

	// Sort the planets by the various criteria.
	sorthelper.NewSorter(planets).OrderedBy(name)
	fmt.Println("By name:", planets)

	sorthelper.NewSorter(planets).OrderedBy(mass)
	fmt.Println("By mass:", planets)

	sorthelper.NewSorter(planets).OrderedBy(distance)
	fmt.Println("By distance:", planets)

	sorthelper.NewSorter(planets).OrderedBy(decreasingDistance)
	fmt.Println("By decreasing distance:", planets)

}
Output:

By name: [{Earth 1 1} {Mars 0.107 1.5} {Mercury 0.055 0.4} {Venus 0.815 0.7}]
By mass: [{Mercury 0.055 0.4} {Mars 0.107 1.5} {Venus 0.815 0.7} {Earth 1 1}]
By distance: [{Mercury 0.055 0.4} {Venus 0.815 0.7} {Earth 1 1} {Mars 0.107 1.5}]
By decreasing distance: [{Mars 0.107 1.5} {Earth 1 1} {Venus 0.815 0.7} {Mercury 0.055 0.4}]
Example (SortMultiKeys)

ExampleMultiKeys demonstrates sorting a struct type using different sets of multiple fields in the comparison. We chain together "Less" functions with MultiSorter, each of which compares a single field.

package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

// A Change is a record of source code changes, recording user, language, and delta size.
type Change struct {
	user     string
	language string
	lines    int
}

var changes = []Change{
	{"gri", "Go", 100},
	{"ken", "C", 150},
	{"glenda", "Go", 200},
	{"rsc", "Go", 200},
	{"r", "Go", 100},
	{"ken", "Go", 200},
	{"dmr", "C", 100},
	{"r", "C", 150},
	{"gri", "Smalltalk", 80},
}

// ExampleMultiKeys demonstrates sorting a struct type using different sets of multiple fields in the comparison.
// We chain together "Less" functions with MultiSorter, each of which compares a single field.
func main() {
	// Closures that order the Change structure.
	user := func(c1, c2 *Change) bool {
		return c1.user < c2.user
	}
	language := func(c1, c2 *Change) bool {
		return c1.language < c2.language
	}
	increasingLines := func(c1, c2 *Change) bool {
		return c1.lines < c2.lines
	}
	decreasingLines := func(c1, c2 *Change) bool {
		return c1.lines > c2.lines // Note: > orders downwards.
	}

	// Simple use: Sort by user.
	sorthelper.NewMultiSorter(changes).OrderedBy(user)
	fmt.Println("By user:", changes)

	// More examples.
	sorthelper.NewMultiSorter(changes).OrderedBy(user, increasingLines)
	fmt.Println("By user,<lines:", changes)

	sorthelper.NewMultiSorter(changes).OrderedBy(user, decreasingLines)
	fmt.Println("By user,>lines:", changes)

	sorthelper.NewMultiSorter(changes).OrderedBy(language, increasingLines)
	fmt.Println("By language,<lines:", changes)

	sorthelper.NewMultiSorter(changes).OrderedBy(language, increasingLines, user)
	fmt.Println("By language,<lines,user:", changes)

}
Output:

By user: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
By user,<lines: [{dmr C 100} {glenda Go 200} {gri Smalltalk 80} {gri Go 100} {ken C 150} {ken Go 200} {r Go 100} {r C 150} {rsc Go 200}]
By user,>lines: [{dmr C 100} {glenda Go 200} {gri Go 100} {gri Smalltalk 80} {ken Go 200} {ken C 150} {r C 150} {r Go 100} {rsc Go 200}]
By language,<lines: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
By language,<lines,user: [{dmr C 100} {ken C 150} {r C 150} {gri Go 100} {r Go 100} {glenda Go 200} {ken Go 200} {rsc Go 200} {gri Smalltalk 80}]
Example (SortWrapper)
package main

import (
	"fmt"
	"sort"

	"github.com/weiwenchen2022/sorthelper"
)

type Grams int

func (g Grams) String() string { return fmt.Sprintf("%dg", int(g)) }

type Organ struct {
	Name   string
	Weight Grams
}

type Organs = sorthelper.Slice[*Organ]

// ByName implements sort.Interface by providing Less and using the Len and
// Swap methods of the embedded Organs value.
type ByName struct{ Organs }

func (s ByName) Less(i, j int) bool { return s.Organs[i].Name < s.Organs[j].Name }

// ByWeight implements sort.Interface by providing Less and using the Len and
// Swap methods of the embedded Organs value.
type ByWeight struct{ Organs }

func (s ByWeight) Less(i, j int) bool { return s.Organs[i].Weight < s.Organs[j].Weight }

func main() {
	s := []*Organ{
		{"brain", 1340},
		{"heart", 290},
		{"liver", 1494},
		{"pancreas", 131},
		{"prostate", 62},
		{"spleen", 162},
	}

	sort.Sort(ByWeight{s})
	fmt.Println("Organs by weight:")
	printOrgans(s)

	sort.Sort(ByName{s})
	fmt.Println("Organs by name:")
	printOrgans(s)

}

func printOrgans(s []*Organ) {
	for _, o := range s {
		fmt.Printf("%-8s (%v)\n", o.Name, o.Weight)
	}
}
Output:

Organs by weight:
prostate (62g)
pancreas (131g)
spleen   (162g)
heart    (290g)
brain    (1340g)
liver    (1494g)
Organs by name:
brain    (1340g)
heart    (290g)
liver    (1494g)
pancreas (131g)
prostate (62g)
spleen   (162g)

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Float64s

func Float64s[E ~float64](x []E)

Float64s sorts a slice of floats in increasing order. Not-a-number (NaN) values are ordered before other values.

Example
package main

import (
	"fmt"
	"math"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myfloat64 float64
	s := []myfloat64{5.2, -1.3, 0.7, -3.8, 2.6} // unsorted
	sorthelper.Float64s(s)
	fmt.Println(s)

	s = []myfloat64{myfloat64(math.Inf(1)), myfloat64(math.NaN()), myfloat64(math.Inf(-1)), 0.0} // unsorted
	sorthelper.Float64s(s)
	fmt.Println(s)

}
Output:

[-3.8 -1.3 0.7 2.6 5.2]
[NaN -Inf 0 +Inf]

func Float64sAreSorted

func Float64sAreSorted[E ~float64](x []E) bool

Float64sAreSorted reports whether the slice s is sorted in increasing order, with not-a-number (NaN) values before any other values.

Example
package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myfloat64 float64
	s := []myfloat64{0.7, 1.3, 2.6, 3.8, 5.2} // sorted ascending
	fmt.Println(sorthelper.Float64sAreSorted(s))

	s = []myfloat64{5.2, 3.8, 2.6, 1.3, 0.7} // sorted descending
	fmt.Println(sorthelper.Float64sAreSorted(s))

	s = []myfloat64{5.2, 1.3, 0.7, 3.8, 2.6} // unsorted
	fmt.Println(sorthelper.Float64sAreSorted(s))

}
Output:

true
false
false

func Ints

func Ints[E constraints.Integer](x []E)

Ints sorts a slice of ints in increasing order.

Example
package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myint int
	s := []myint{5, 2, 6, 3, 1, 4} // unsorted
	sorthelper.Ints(s)
	fmt.Println(s)
}
Output:

[1 2 3 4 5 6]

func IntsAreSorted

func IntsAreSorted[E constraints.Integer](x []E) bool

IntsAreSorted reports whether the slice x is sorted in increasing order.

Example
package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myint int
	s := []myint{1, 2, 3, 4, 5, 6} // sorted ascending
	fmt.Println(sorthelper.IntsAreSorted(s))

	s = []myint{6, 5, 4, 3, 2, 1} // sorted descending
	fmt.Println(sorthelper.IntsAreSorted(s))

	s = []myint{3, 2, 4, 1, 5} // unsorted
	fmt.Println(sorthelper.IntsAreSorted(s))

}
Output:

true
false
false
func Search[E constraints.Ordered](a []E, x E) int

Search searches for x in a sorted slice of a and returns the index. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.

func SearchFloat64s

func SearchFloat64s[E ~float64](a []E, x E) int

SearchFloat64s searches for x in a sorted slice of float64s and returns the index as specified by Search. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.

Example

This example demonstrates searching for float64 in a list sorted in ascending order.

package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myfloat64 float64
	a := []myfloat64{1.0, 2.0, 3.3, 4.6, 6.1, 7.2, 8.0}

	x := myfloat64(2.0)
	i := sorthelper.SearchFloat64s(a, x)
	fmt.Printf("found %g at index %d in %v\n", x, i, a)

	x = myfloat64(0.5)
	i = sorthelper.SearchFloat64s(a, x)
	fmt.Printf("%g not found, can be inserted at index %d in %v\n", x, i, a)

}
Output:

found 2 at index 1 in [1 2 3.3 4.6 6.1 7.2 8]
0.5 not found, can be inserted at index 0 in [1 2 3.3 4.6 6.1 7.2 8]

func SearchInts

func SearchInts[E constraints.Integer](a []E, x E) int

SearchInts searches for x in a sorted slice of ints and returns the index as specified by Search. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.

Example

This example demonstrates searching for int in a list sorted in ascending order.

package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type myint int
	a := []myint{1, 2, 3, 4, 6, 7, 8}

	x := myint(2)
	i := sorthelper.SearchInts(a, x)
	fmt.Printf("found %d at index %d in %v\n", x, i, a)

	x = myint(5)
	i = sorthelper.SearchInts(a, x)
	fmt.Printf("%d not found, can be inserted at index %d in %v\n", x, i, a)

}
Output:

found 2 at index 1 in [1 2 3 4 6 7 8]
5 not found, can be inserted at index 4 in [1 2 3 4 6 7 8]

func SearchStrings

func SearchStrings[E ~string](a []E, x E) int

SearchStrings searches for x in a sorted slice of strings and returns the index as specified by Search. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.

func SliceIsSorted

func SliceIsSorted[E constraints.Ordered](x []E) bool

SliceIsSorted reports whether the slice s is sorted in increasing order according to the operator <.

func SliceSort

func SliceSort[E constraints.Ordered](x []E)

SliceSort sorts the slice x as determined by the operator <, in increasing order.

The sort is not guaranteed to be stable: equal elements may be reversed from their original order. For a stable sort, use StableSort.

func SliceStable

func SliceStable[E constraints.Ordered](x []E)

SliceStable sorts the slice x using the operator <, in ascending order, keeping equal elements in their original order.

func Strings

func Strings[E ~string](x []E)

Strings sorts a slice of strings in increasing order.

Example
package main

import (
	"fmt"

	"github.com/weiwenchen2022/sorthelper"
)

func main() {
	type mystring string
	s := []mystring{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}
	sorthelper.Strings(s)
	fmt.Println(s)
}
Output:

[Alpha Bravo Delta Go Gopher Grin]

func StringsAreSorted

func StringsAreSorted[E ~string](x []E) bool

StringsAreSorted reports whether the slice x is sorted in increasing order.

Types

type Float64Slice

type Float64Slice[E ~float64] struct{ Slice[E] }

Float64Slice implements sort.Interface by providing Less and using the Len and Swap methods of the embedded slice value, sorting in increasing order, with not-a-number (NaN) values ordered before other values.

func (Float64Slice[E]) IsSorted

func (x Float64Slice[E]) IsSorted() bool

IsSorted is a convenience method: x.IsSorted() calls sort.IsSorted(x).

func (Float64Slice[E]) Less

func (x Float64Slice[E]) Less(i, j int) bool

Less reports whether x[i] should be ordered before x[j], as required by the sort Interface. Note that floating-point comparison by itself is not a transitive relation: it does not report a consistent ordering for not-a-number (NaN) values. This implementation of Less places NaN values before any others, by using:

x[i] < x[j] || (math.IsNaN(x[i]) && !math.IsNaN(x[j]))

func (Float64Slice[E]) Reverse

func (x Float64Slice[E]) Reverse()

Reverse is a convenience method: x.Reverse() calls sort.Sort(sort.Reverse(x)).

func (Float64Slice[E]) Search

func (p Float64Slice[E]) Search(x E) int

Search returns the result of applying SearchFloat64s to the receiver and x.

func (Float64Slice[E]) Sort

func (x Float64Slice[E]) Sort()

Sort is a convenience method: x.Sort() calls sort.Sort(x).

func (Float64Slice[E]) Stable

func (x Float64Slice[E]) Stable()

Stable is a convenience method: x.Stable() calls sort.Stable(x).

type IntSlice

type IntSlice[E constraints.Integer] struct{ Slice[E] }

IntSlice implements sort.Interface by providing Less and using the Len and Swap methods of the embedded slice value, sorting in increasing order.

func (IntSlice[E]) IsSorted

func (x IntSlice[E]) IsSorted() bool

IsSorted is a convenience method: x.IsSorted() calls sort.IsSorted(x).

func (IntSlice[E]) Less

func (x IntSlice[E]) Less(i, j int) bool

func (IntSlice[E]) Reverse

func (x IntSlice[E]) Reverse()

Reverse is a convenience method: x.Reverse() calls sorrt.Sort(sort.Reverse(x)).

func (IntSlice[E]) Search

func (p IntSlice[E]) Search(x E) int

Search returns the result of applying SearchInts to the receiver and x.

func (IntSlice[E]) Sort

func (x IntSlice[E]) Sort()

Sort is a convenience method: x.Sort() calls sort.Sort(x).

func (IntSlice[E]) Stable

func (x IntSlice[E]) Stable()

Stable is a convenience method: x.Stable() calls sort.Stable(x).

type MultiSorter

type MultiSorter[E any] struct {
	// contains filtered or unexported fields
}

MultiSorter implements the Sort interface, sorting the slice within.

func NewMultiSorter

func NewMultiSorter[E any](s []E) *MultiSorter[E]

NewMultiSorter returns a MulitSorter that sorts the argument slice. Call its OrderedBy method to sort the slice within using the less functions, in order.

func (*MultiSorter[E]) Len

func (ms *MultiSorter[E]) Len() int

func (*MultiSorter[E]) Less

func (ms *MultiSorter[E]) Less(i, j int) bool

Less is part of sort.Interface. It is implemented by looping along the less functions until it finds a comparison that discriminates between the two items (one is less than the other). Note that it can call the less functions twice per call.

func (*MultiSorter[E]) OrderedBy

func (ms *MultiSorter[E]) OrderedBy(less ...func(e1, e2 *E) bool)

OrderedBy sorts the slice within according to the less functions, in order. The sort is not guaranteed to be stable. For a stable sort, use StableBy.

func (*MultiSorter[E]) StableBy

func (ms *MultiSorter[E]) StableBy(less ...func(e1, e2 *E) bool)

StableBy sorts the slice within in ascending order as determined by the less functions, in order, while keeping the original order of equal elements.

func (*MultiSorter[E]) Swap

func (ms *MultiSorter[E]) Swap(i, j int)

type Slice

type Slice[E any] []E

Slice help implements sort.Interface by providing Len and Swap methods for embedding value.

func (Slice[E]) Len

func (x Slice[E]) Len() int

func (Slice[E]) Swap

func (x Slice[E]) Swap(i, j int)

type Sorter

type Sorter[E any] struct {
	// contains filtered or unexported fields
}

Sorter joins a by function and a slice s to be sorted.

func NewSorter

func NewSorter[E any](s []E) *Sorter[E]

NewSorter returns a Sorter that sorts the slice s. Call its OrderedBy method to sort the slice within using the by functions.

func (*Sorter[E]) Len

func (s *Sorter[E]) Len() int

func (*Sorter[E]) Less

func (s *Sorter[E]) Less(i, j int) bool

Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.

func (*Sorter[E]) OrderedBy

func (s *Sorter[E]) OrderedBy(by func(e1, e2 *E) bool)

OrderedBy sorts the slice within according to the by function. The sort is not guaranteed to be stable. For a stable sort, use StableBy.

func (*Sorter[E]) StableBy

func (s *Sorter[E]) StableBy(by func(e1, e2 *E) bool)

StableBy sorts the slice within according to the by function, while keeping the original order of equal elements.

func (*Sorter[E]) Swap

func (s *Sorter[E]) Swap(i, j int)

type StringSlice

type StringSlice[E ~string] struct{ Slice[E] }

StringSlice implements sort.Interface by providing Less and using the Len and Swap methods of the embedded slice value, sorting in increasing order.

func (StringSlice[E]) IsSorted

func (x StringSlice[E]) IsSorted() bool

IsSorted is a convenience method: x.IsSorted() calls sort.IsSorted(x).

func (StringSlice[E]) Less

func (x StringSlice[E]) Less(i, j int) bool

func (StringSlice[E]) Reverse

func (x StringSlice[E]) Reverse()

Reverse is a convenience method: x.Reverse() calls sort.Sort(sort.Reverse(x)).

func (StringSlice[E]) Search

func (p StringSlice[E]) Search(x E) int

Search returns the result of applying SearchStrings to the receiver and x.

func (StringSlice[E]) Sort

func (x StringSlice[E]) Sort()

Sort is a convenience method: x.Sort() calls sort.Sort(x).

func (StringSlice[E]) Stable

func (x StringSlice[E]) Stable()

Stable is a convenience method: x.Stable() calls sort.Stable(x).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL