I want to sort a slice of []uint. Does this make sense? Is there something I'm missing about uints that make them unsortable? I notice that the sort package has an IntSlice and Float64Slice, but nothing for uint.
If uints are sortable, then can I just copy the same implementation for Len(), Less(i, j int) and Swap(i, j int) that they've used for the sort.IntSlice?
As for 1.7, you can sort any slice that implements sort.Interface for an alias type of your []uint slice and using sort.Sort(Interface) . In Go 1.8, you will have the option to use sort.Slice. See the example here
Related
In Go is possible to compare two strings:
package main
func main() {
println("ab" > "ba")
println("ab" < "ba")
}
false
true
Program exited.
https://go.dev/play/p/svkLf6R84SC
How do I perform a similar operation on two slices? e.g. []int{1,2} > []int{2,1}.
I need this to sort a slice of slices of ints. So I need an implementation of sort.Interface.
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
It would be better if this implementation is generic.
Writing a comparator and a less function for sort.Slices would be the most effective way to do this within the standard library.
Stepping outside of that slightly (until generics usage within the standard library is finalized), in Go 1.18 we can use the golang.org/x/exp/constraints and golang.org/x/exp/slices packages to generically sort a slice of slices of ordered values: https://go.dev/play/p/MA0lY6POVFR
func SortSlices[T constraints.Ordered](s [][]T) {
sort.Slice(s, func(i, j int) bool {
return slices.Compare(s[i], s[j]) < 0
})
}
Documentation about slices.Compare:
Compare compares the elements of s1 and s2. The elements are compared sequentially, starting at index 0, until one element is not equal to the other. The result of comparing the first non-matching elements is returned. If both slices are equal until one of them ends, the shorter slice is considered less than the longer one. The result is 0 if s1 == s2, -1 if s1 < s2, and +1 if s1 > s2. Comparisons involving floating point NaNs are ignored.
Please see this playground. I have a slice with some data. Now I want to sort this slice, but not on a value inside one of the values, but I want to sort it on the number of occurrences of one of the values.
Unfortunately I don't have a clue how to fix this. Can someone please point me to the right direction?
I know I can do this:
sort.Slice(messages, func(i, j int) bool {
return messages[i].SupplierID < messages[j].SupplierID
})
This will sort the slice, but it will start with the "higest" supplierID. but what I want is to sort on the number of occurrences: the ones with the lease number of supplierIDs first.
Iterate over the slice, populate a map of occurrences, then sort the slice based on the number of occurrences:
supplierCounts := make(map[int]int)
for _, msg := range messages {
supplierCounts[msg.SupplierID]++
}
sort.Slice(messages, func(i, j int) bool {
return supplierCounts[messages[i].SupplierID] < supplierCounts[messages[j].SupplierID]
})
https://play.golang.org/p/YMWPP2JBC2P
I have the following multivariate array:
x := [2][3]int{
{3, 2, 1},
{3, 2, 1},
}
Both rows and columns are fixed-size.
I'm trying to check that the rows are sorted, and I undertand the sort function requires arrays without a known size. How can I ask the go to treat the item with a fixed-, known size as if it had an unknown size?
var allTrue bool = true
for i := range x {
t := sort.Ints(x[i]) == []int{1, 2, 3}
allTrue = allTrue && t
}
I get:
./main.go:xx:yy: sort.Ints(x[i]) used as value
./main.go:xx:yy: cannot use x[i] (type [3]int) as type []int in argument to sort.Ints
Am I reading this error message correctly?
Notwithstanding this other answer, which provides guidance regarding appropriate slicing to use the sort package, I have added this answer to provide more description on some further issues with the code you have posted. I hope this aids your understanding of the Go language.
Introduction to Slices
I undertand the sort function requires arrays without a known size [sic]
As others have said, this is not the terminology to describe this concept in Go. All Go arrays are of fixed size, as defined by the language spec. As you know, arrays are of type [N]T for an array which contains some non-negative number N of elements of type T. This is fixed at compile time and never changes during runtime of your program.
"Arrays without a known size" most closely maps to slices. Slices are distinct types in Go which allow for representation of sequences of data of a particular type, where their length is managed dynamically by the Go runtime. They are of type []T for elements of type T. In particular, their size is not part of their type definition and can change at runtime. For some slice variable x []T, the implementation provides:
an internal backing array of similar elemental type, where the implementation manages the allocation of memory and expansion of the array as the slice length increases
its length len(x) – denoting the number of elements the slice currently contains
its capacity cap(x) – the total length of the slice plus the additional extent of the backing array, which may extend beyond the length due to slicing operations restricting the view on the array or a larger array being allocated by the runtime to allow for appending more items to the slice.
See the Tour of Go and the language spec on slices for more details.
Resolving the problem with the code
As noted above, slices are of distinct type to arrays, so you cannot use something of type [N]T for some N and T where something of type []T is required.
sort.Ints sorts a slice of integers in-place – it has type signature func Ints(a []int). Your call sort.Ints(x[i]) indexes the array x at index i, which will return an array of type [3]int. This is incompatible with the sort function and leads to the compile-time error you observe.
To obtain a slice from an array, you use a slice expression. Such expressions allow arrays, slices and some other types to be used to construct new slices.
Slice expressions are given in the form a[low : high] where low and high are optional integers providing indices into the backing array or slice which specify the range to return in the new slice. The language spec link above has more details which I recommend you read; suffice to say the simplest slice expression a[:] for some array or slice a is syntactic sugar to mean a[0:len(a)-1], i.e. transform the array/slice into a slice of the same length.
Using this trick, obtain a slice of type []int from your multi-dimensional array by slicing: x[i][:]:
x[i] returns an array of type [3]int, as before
slicing the returned array returns a slice of type []int, which is compatible with sort.Ints.
sort.Ints does not return a value, and slices are not comparable
Even if you fix these issues with your code, there remain two issues with the following line:
t := sort.Ints(x[i]) == []int{1, 2, 3}
sort.Ints sorts in-place; it does not return a value, so the equality test is meaningless.
sort.Ints operates on slices, which are not comparable. It is not possible to call A == B where either A or B is a slice, unless either A or B is the special identifier nil. This is a subtle point which is covered in the language spec. (Aside: read that page, as you will note arrays are comparable.)
As you cannot compare slices directly using the == equality operator, verifying element-wise equality of slices requires:
Slices to be of the same length (dissimilar lengths implies one slice has more elements than the other)
Elements at each index of one slice are identical to other slices.
(I am ignoring the fact that one slice may have a dissimilar capacity to another, as we only care about the element-wise equality.)
This can be verified by looping through one of the slices and verifying elements at each index correspond at the same index in the other slice. This example code provides an example of that (playground link):
package main
import (
"fmt"
)
func CheckEquality(a, b []int) bool {
// Slices of dissimilar length are not equal
if len(a) != len(b) {
return false
}
for i, el := range a {
if b[i] != el {
return false
}
}
return true
}
func main() {
var mySlice = []int{1, 2, 3, 4, 5}
var mySlice2 = []int{1, 2, 3, 4, 5} // same as mySlice
var otherSlice = []int{5, 6, 7, 8, 9} // dissimilar slice
var longSlice = []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println(CheckEquality(mySlice, mySlice2)) // Expect true
fmt.Println(CheckEquality(mySlice, otherSlice)) // Expect false
fmt.Println(CheckEquality(mySlice, longSlice)) // Expect false
}
You have to slice the array with the [:] operator before you can use it with the sort package. See: A Tour of Go: Slices and the "sort" package godoc.
Also, you can check whether the slice is sorted more efficiently than sorting it, using sort.IntsAreSorted([]int), like this.
var allTrue bool = true
for i := range x {
if !sort.IntsAreSorted(x[i][:]) {
allTrue = false
break
}
}
You can get a slice from an array by using the [:] operator, e.g.:
arr := [3]int{1, 2, 3}
slc := arr[:] // []int{1, 2, 3}, backed by arr
As such, you could use the sort.Ints(...) function:
sort.Ints(x[0][:])
sort.Ints(x[1][:])
// Now both elements of "x" are sorted.
I have the following definition:
func (c *Collector) RegisterSource(f func() []interface{}) {
c.source = f
}
I attempt to call it as follows but get an error:
func source() []int {
return []int{ 0, 1, 2, 3, 4 }
}
...
c.RegisterSource(source)
This is met with:
cannot use source (type func() []int) as type func() []interface {} in argument to c.RegisterSource
The relevant Go FAQ entry states that []T and []interface{} «do not have the same representation in memory».
To understand why, let's dissect two things:
A slice is a backing storage array plus several integers containing the size and capacity
of the slice.
In Go, arrays are not somehow "high-level"; on the contrary,
the layout of the elements they contain is strictly defined: they are all
contained in a contiguous region of memory, adjacent to each other.
This means, that in the backing array of a slice []T, elements are of
type T, and each of them occupies a region of memory of a size natural
for that type T, and all these regions are all adjacent to each other
in a single contiguous memory block.
That means, each element of a slice []int occupies exactly 64 bits
(8 bytes) on a 64-bit platform — the amount of memory a single int value
occupies.
A value of any interface type, including the empty interface,
interface{}, is represented as a structure containing two pointers,
something like:
type iface struct {
realType *typeInfo
realValue *dataType
}
(More on how interfaces are represented — here).
All of the above means in a slice []interface{} each element occupies the
region of memory the size of two pointers, and these two pointers contain
addresses of other variables in memory — as opposed to mere integer values
contained by elements of []int.
And this, in turn, means you can't just "cast" []int "to" []interface{} — simply because a value stored in any element of []int (an int) is
incompatible in its structure (memory layout) with an element
of []interface{} (a struct containing two pointers).
To produce one from another, you need to allocate a slice and convert each
element of the source slice to a matching element of the destination one.
Finally, this means if a function returns a slice of type []int,
that slice cannot be directly processed by code expecting slices of
type []interface{} (and vice-versa), and this explains why
the two function signatures from your question represent incompatible
types.
Because []int and []interface are 2 different types of slices and go does not allow automatic conversion between the 2.
https://github.com/golang/go/wiki/InterfaceSlice
all you can do is change this
func source() []int {
return []int{ 0, 1, 2, 3, 4 }
}
into that
func source() []interface{} {
return []interface{}{ 0, 1, 2, 3, 4 }
}
in order to fit the function signature you defined for RegisterSource.
I have a slice of 10 maps, how can I sort by one of the values?
[{"name":"a","score":100},
{"name":"z","score":150},
{"name":"s","score":120},
{"name":"x","score":110},
{"name":"r","score":10},
{"name":"b","score":1300},
{"name":"b","score":1500},
{"name":"w","score":1002},
{"name":"o","score":140},
{"name":"q","score":101}]
I want to sort the slice with the score value, in descending order, but I'm at a loss of how.
just a simple sort.Slice.
sort.Slice(information,
func(i, j int) bool {
return information[i].Difference > information[j].Difference
})