order
Package order enables easier ordering and comparison tasks.
This package provides functionality to easily define and apply order on values. It works out of
the box for most primitive types and their pointer versions, and enable order of any object using
three-way comparison with a given
func(T, T) int
function, or by implementing the generic interface: func (T) Compare(T) int
.
Supported Tasks:
Types and Values
Order between values can be more forgiving than strict comparison. This library allows sensible
type conversions. A type U
can be used in order function of type T
in the following cases:
-
U
is a pointer (or pointers chain) to a T
.
-
T
is a pointer (or pointers chain) to a U
.
-
T
and U
are of the same kind.
-
T
and U
are of the same number kind group (int?, uint?, float?, complex?) and U
's bits
number is less or equal to T
's bits number.
-
U
and T
are assignable structs.
Usage
Using this library might be less type safe - because of the usage of interfaces API, and less
efficient - because of the use of reflection. On the other hand, this library reduce chances for
errors by providing a well tested code and more readable code. See below how some order tasks
can be translated to be used by this library.
type person struct {
name string
age int
}
var persons []person
// Sort persons (by name and then by age)
-lessPersons := func(i, j int) bool {
- nameCmp := strings.Compare(persons[i].name, "joe")
- if nameCmp == 0 {
- return persons[i].age < persons[i].age
- }
- return nameCmp < 0
-}
-sort.Slice(persons, lessPersons)
+orderPersons := order.By(
+ func(a, b person) int { return strings.Compare(a.name, b.name) },
+ func(a, b person) int { return a.age - b.age },
+)
+orderPersons.Sort(persons)
// Search persons for "joe" at age 42:
-searchPersons := func(int i) bool {
- nameCmp := strings.Compare(persons[i].name, "joe")
- if nameCmp == 0 {
- return persons[i].age >= 42
- }
- return nameCmp > 0 {
-}
-i := sort.Search(persons, searchPersons)
-// Standard library search does not guarantee equality, we should check:
-if i >= len(persons) || persons[i].name != "joe" || persons[i].age != 42 {
- i := -1
-}
+i := orderPersons.Search(persons, person{name: "joe", age: 42})
// Another way is that person will implement a `Compare(T) int` method, and the order object
// will know how to handle it:
+func (p person) Compare(other person) int { ... }
+order.Search(persons, person{name: "joe", age: 42})
// Conditions can also be defined on comparable types:
var t, start, end time.Time
-if (t.After(start) || t.Equal(start)) && t.Before(end) { ... }
+if isT := order.Is(t); isT.GreaterEqual(start) && isT.Less(end) { ... }
Examples
A simple example that shows how to use the order library with different basic types.
fmt.Println("now > one-second-ago ?",
Is(time.Now()).Greater(time.Now().Add(-time.Second)))
fmt.Println("foo == bar ?",
Is("foo").Equal("bar"))
if is := Is(3); is.GreaterEqual(3) && is.Less(4) {
fmt.Println("3 is in [3,4)")
}
Output:
now > one-second-ago ? true
foo == bar ? false
3 is in [3,4)
Comparable
A type may implement a func (t T) Compare(other T) int
function. In this case it could be just
used with the order package functions.
oranges := []orange{5, 2, 24}
Sort(oranges)
fmt.Println(oranges)
Output:
[2 5 24]
Complex
An example of ordering struct with multiple fields with different priorities.
type person struct {
name string
age int
}
orderPersons := By(
func(a, b person) int { return strings.Compare(a.name, b.name) },
func(a, b person) int { return a.age - b.age },
).Reversed()
list := []person{
{"Bar", 10},
{"Foo", 10},
{"Bar", 11},
}
orderPersons.Sort(list)
fmt.Println("Reversed:", list)
fmt.Println("Index of {Foo 10}:", orderPersons.Search(list, person{"Foo", 10}))
Output:
Reversed: [{Foo 10} {Bar 11} {Bar 10}]
Index of {Foo 10}: 0
SliceOperations
list := []int{2, 1, 3}
Sort(list)
fmt.Println("Sorted:", list)
fmt.Println("Index of 2:", Search(list, 2))
minI, maxI := MinMax(list)
fmt.Printf("Min: %d, max: %d\n", list[minI], list[maxI])
Select(list, len(list)/2)
fmt.Printf("Median: %d\n", list[1])
Output:
Sorted: [1 2 3]
Index of 2: 1
Min: 1, max: 3
Median: 2
Created by goreadme