Sorting a slice of integers - go

My intention is to sort the values given in the slice of ints . I do not want to use the sort package and want to implement the sort function . The issue is when I try to use a index to compare the slice elements i get out of bounds error . What is correct way to modify a slice ?
func sortSlice( sli []int ) {
j := 0
i := 1
for range sli {
if( sli[j] > sli[j+1] ) {
var temp int = sli[j];
sli[i] = sli[j]
sli[j] = temp
}
j++
}
}

You range over sli meaning you iterate len(sli) times so j goes from 0 to len(sli)-1. Now you compare element j with element j+1. For the last iteration this means you compare element len(sli)-1 with element len(sli). This last index is the problem. There is no element len(sli) because sli's indices go from 0 to len(sli)-1.
Also note that in Go you can say sli[i], sli[j] = sli[j], sli[i] to swap two items. That said, your code cannot work since there is no i defined anywhere.
Next on the list of issues is that this is not all of the bubble algorithm that I think you are going for. You only iterate over the slice once but this will not sort it. You would have to repeat the loop you have until no more swaps happen.

If I understand it right, you want to do your custom implementation, but not sure why don't want to use sort package. You can do custom sorting by overriding go#interface.
For example
You can write a custom sort in go and call it with the sort package. basically you can override sort function for interface and can change the behaviour according to your needs. you can create a struct that takes in your data, as per below example and override the functions Len() , Swap() , Less()
type Sortslice struct {
Sli []int
}
func (s Sortslice) Len() int {
return len(s.Sli)
}
func (s Sortslice) Swap(i, j int) {
s.Sli[i], s.Sli[j] = s.Sli[j], s.Sli[i]
}
func (s Sortslice) Less(i, j int) bool {
if s.Sli[i] > s.Sli[j] {
return true
} else {
return false
}
}
After making the structure you can pass your data into it and call the sort method over the []interface using sort.sort() function. this will use your logic to sort the slice.
var data = []int{5,6,8,1,9,10}
sortedSlice := Sortslice{data}
sort.Sort(sortedSlice);
It's better to use sort.Sort since it takes care like what to do (use merge sort, quick sort).
But if you want to do everything by yourself follow the source code of sort.sort() and in a similar manner write your custom things
source : https://yourbasic.org/golang/how-to-sort-in-go/

Related

Optimal way to add or remove slice element in Go without broke elements order

Assume I have []struct{} and I need to know whether an element with id = A exists in the slice. If exists, the element will be removed or moved to index 0 according to request in user input. So, how to find an element in golang slice in optimal way without check each element? Or, is using slice.contains(obj) enough? Then, if the element exists, I will do action according to request in user input. If the request is remove, I will remove it without broke the elements order. But if the request is add, I will move the element to index 0.
Note: The function will be often called.
Thank you.
It is not difficult to write function to find element by iterating over slice:
func contains(s []your_struct, e int) (bool, int) {
for idx, a := range s {
if a.id == e {
return true, idx
}
}
return false, -1
}
If you a going to call the function often it may be useful to sort the slice by id field and implement binary search over slice of your_struct.
If the slice is not very big you can create additional data structure - map[int]int and keep the indexes of elements of the slice in this map. But in this case you need to synchronize content of your slice and the map when you are modifying one of them:
your_map := make(map[int]int)
if idx, ok := your_map[id]; ok {
// ...
}
If you need to check many times then
it's better to create a map[string]int of id field one time.
And every time just check map contains that id or not
Here,id as key and slice index as value
mp := make(map[string]int)
for idx, a := range yourStuctSlice {
mp[a.id] = idx
}
if idx, ok := mp[id]; ok {
// remove the element using idx
}
If new element added in slice then update the map also
mp[newElement.id] = true
If you want to remove searched element you can remove by slice index
func RemoveIndex(s []yourStuct, index int) []int {
return append(s[:index], s[index+1:]...)
}
if idx, ok := mp[id]; ok {
yourStuctSlice = RemoveIndex(yourStuctSlice , idx)
delete(mp , id); // Remove from map also for next search
}

creating generic functions for multi type arrays in Go

I am trying to create a generic function that can handle actions on slices in Go... for instance, append an item of any type to a slice of that same type. This is simply a generic purpose for a more complex solution, but overall the issue boils down to this example:
package main
type car struct {
make string
color string
}
type submarine struct {
name string
length int
}
func genericAppender(thingList interface{}, thing interface{}) []interface{} {
return append(thingList, thing)
}
func main() {
cars := make([]car, 0, 10)
cars[0] = car{make: "ford", color: "red"}
cars[1] = car{make: "chevy", color: "blue"}
subs := make([]submarine, 0, 10)
subs[0] = submarine{name: "sally", length: 100}
subs[1] = submarine{name: "matilda", length: 200}
newCar := car{make: "bmw", color: "white"}
genericAppender(&cars, newCar)
}
The code playground is at this location
The above errors as follows:
prog.go:14: first argument to append must be slice; have interface {}
After this change you're still getting a runtime error (index out of range) however the problem is that thingList is not of type []interface{} but rather interface{} so you can't append to it. Here's an updated version of your code on playground that does a type assertion to convert it to an []interface{} in line with the append. In reality you need to do that on a separate line and check for errors.
https://play.golang.org/p/YMed0VDZrv
So to put some code here;
func genericAppender(thingList interface{}, thing interface{}) []interface{} {
return append(thingList.([]interface{}), thing)
}
will solve the basic problem you're facing. As noted, you still get runtime errors when indexing into the slice. Also, you could change the argument to avoid this by making it;
func genericAppender(thingList []interface{}, thing interface{}) []interface{} {
return append(thingList, thing)
}
Here's a complete example of the second type; https://play.golang.org/p/dIuW_UG7XY
Note I also corrected the runtime error. When you use make with 3 args they are, in this order, type, length, capacity. This means the length of the array is 0 so when you try to assign to indexes 0 and 1 it was causing a panic for IndexOutoFRange. Instead I removed the middle argument so it's make([]interface{}, 10) meaning the length is initially set to 10 so you can assign to those indexes.
In the answer above if you do the following then it throws error. This is what the original question was about:
//genericAppender(subs, newCar). // Throws "cannot use subs (type []submarine) as type []interface {} in argument to genericAppender"
The trick is to convert your slice of specific type into a generic []interface{}.
func convertToGeneric(thingList interface{}) []interface{} {
input := reflect.ValueOf(thingList)
length := input.Len()
out := make([]interface{},length)
for i:=0 ;i < length; i++ {
out[i] = input.Index(i).Interface()
}
return out
}
This you can call the function like this:
genericAppender(convertToGeneric(subs), newCar)
You can check modified working code here: https://play.golang.org/p/0_Zmme3c8lT
With Go 1.19 (Q4 2022), no need for interface, or "convert your slice of specific type into a generic []interface{}"
CL 363434 comes with a new slices packages:
// Package slices defines various functions useful with slices of any type.
// Unless otherwise specified, these functions all apply to the elements
// of a slice at index 0 <= i < len(s).
package slices
import "constraints"
// Grow increases the slice's capacity, if necessary, to guarantee space for
// another n elements. After Grow(n), at least n elements can be appended
// to the slice without another allocation. If n is negative or too large to
// allocate the memory, Grow panics.
func Grow[S ~[]T, T any](s S, n int) S {
return append(s, make(S, n)...)[:len(s)]
}
// Equal reports whether two slices are equal: the same length and all
// elements equal. If the lengths are different, Equal returns false.
// Otherwise, the elements are compared in index order, and the
// comparison stops at the first unequal pair.
// Floating point NaNs are not considered equal.
func Equal[T comparable](s1, s2 []T) bool {
if len(s1) != len(s2) {
return false
}
for i, v1 := range s1 {
v2 := s2[i]
if v1 != v2 {
return false
}
}
return true
}
// ...
Ian Lance Taylor confirms in issue 45955:
This package is now available at golang.org/x/exp/slices.
Per this thread, it will not be put into standard library until the 1.19 release.
We may of course adjust it based on anything we learn about having it in x/exp.

Can we write a generic array/slice deduplication in go?

Is there a way to write a generic array/slice deduplication in go, for []int we can have something like (from http://rosettacode.org/wiki/Remove_duplicate_elements#Go ):
func uniq(list []int) []int {
unique_set := make(map[int] bool, len(list))
for _, x := range list {
unique_set[x] = true
}
result := make([]int, len(unique_set))
i := 0
for x := range unique_set {
result[i] = x
i++
}
return result
}
But is there a way to extend it to support any array? with a signature like:
func deduplicate(a []interface{}) []interface{}
I know that you can write that function with that signature, but then you can't actually use it on []int, you need to create a []interface{} put everything from the []int into it, pass it to the function then get it back and put it into a []interface{} and go through this new array and put everything in a new []int.
My question is, is there a better way to do this?
While VonC's answer probably does the closest to what you really want, the only real way to do it in native Go without gen is to define an interface
type IDList interface {
// Returns the id of the element at i
ID(i int) int
// Returns the element
// with the given id
GetByID(id int) interface{}
Len() int
// Adds the element to the list
Insert(interface{})
}
// Puts the deduplicated list in dst
func Deduplicate(dst, list IDList) {
intList := make([]int, list.Len())
for i := range intList {
intList[i] = list.ID(i)
}
uniques := uniq(intList)
for _,el := range uniques {
dst.Insert(list.GetByID(el))
}
}
Where uniq is the function from your OP.
This is just one possible example, and there are probably much better ones, but in general mapping each element to a unique "==able" ID and either constructing a new list or culling based on the deduplication of the IDs is probably the most intuitive way.
An alternate solution is to take in an []IDer where the IDer interface is just ID() int. However, that means that user code has to create the []IDer list and copy all the elements into that list, which is a bit ugly. It's cleaner for the user to wrap the list as an ID list rather than copy, but it's a similar amount of work either way.
The only way I have seen that implemented in Go is with the clipperhouse/gen project,
gen is an attempt to bring some generics-like functionality to Go, with some inspiration from C#’s Linq and JavaScript’s underscore libraries
See this test:
// Distinct returns a new Thing1s slice whose elements are unique. See: http://clipperhouse.github.io/gen/#Distinct
func (rcv Thing1s) Distinct() (result Thing1s) {
appended := make(map[Thing1]bool)
for _, v := range rcv {
if !appended[v] {
result = append(result, v)
appended[v] = true
}
}
return result
}
But, as explained in clipperhouse.github.io/gen/:
gen generates code for your types, at development time, using the command line.
gen is not an import; the generated source becomes part of your project and takes no external dependencies.
You could do something close to this via an interface. Define an interface, say "DeDupable" requiring a func, say, UniqId() []byte, which you could then use to do the removing of dups. and your uniq func would take a []DeDupable and work on it

How to create a literal slice of an alias to a builtin type in Go

I have some golang code that manipulates slices of an interface type (Comparable). To test my code, I want to create some fake data and operate on it. However, I'm having trouble doing this in a way that is not incredibly tedious. The only thing I can think to do is create a new type for testing (in this case an alias of type int) that satisfies the Comparable interface, and then feed my tests literal slices of that type. I envision it looking something like the following:
type Comparable interface {
LT(Comparable) bool
AsFloat() float64
}
type testInt int
func (self testInt) LT(other Comparable) bool {
return float64(self) < other.AsFloat()
}
func (self testInt) AsFloat() float64 {
return float64(self)
}
func TestAFunction(t *testing.T) {
FunctionToTest([]Comparable{7, 4, 2, 1})
....
}
However, with this example, the compiler will complain that type int cannot be used as a Comparable. I understand why this is happening, but I'm not sure how to solve it. First, I don't know how to create a literal of type testInt. Second, I have to write a significant number of these functions. Working with literal ints is far more convenient for my purposes.
Is there a way to work with type aliases of builtin types such that the compiler can correctly infer the correct type of literals with a minimum of code?
Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?
func NewWhatevers(a ...int) (r []Whatever) {
r = make([]Whatever, len(a))
for i, v := range a {
r[i] = Whatever(v)
}
return
}
...
myWhatevers := NewWhatevers(7, 4, 2, 1)
There are a number of ways to accomplish this. The problem, as you correctly state, is that the Go compiler cannot automatically convert int to Comparable (since doing so would require finding all possible equivalent types, and figuring out which of those equivalent types satisfy the Comparable interface, and then if there are more than one... you get the idea). Thus, you'll have to do one of two things:
Write an explicit type conversion:
FunctionToTest([]Comparable{ testInt(7), testInt(4), testInt(2), testInt(1) })
However, if you need a lot of literals, this could get really annoying. Thus, you could also:
Write a function to convert []int to []Comparable:
func intToComparable(i []int) []Comparable {
c := make([]Comparable, len(i))
for i, v := range i {
c[i] = testInt(v)
}
return c
}
and then you'd only have to do:
FunctionToTest(intToComparable([]int{ 7, 4, 2, 1 }))
Additionally, is there perhaps a better way to accomplish what I am trying to do, i.e., generate hard data that satisfies an interface for use in testing?
Maybe. The problem you encountered is that []Comparable and []testInt are fundamentally different and cannot be exchanged as the underlying representation in memory is different.
If your code is less about individual item which are Comparable but more about slices of items which can be compared than you could refactor your code to work on whole Slices.
Have a look at how package sort does this: It doesn't operate on a slice of comparables but on a "comparable slice".
// FloatOrder is a slice with comparable and float-convertible elements
type FloatOrder interface {
Less(i, j int) bool // Compare element i and j and return true first is less than the other
Float(i int) float64 // Return element i as a float64
}
type testInts []int
func (n testInts) Less(i, j int) bool {return n[i] < n[j]}
func (n testInts) Float(i int) float64 { return float64(n[i]) }
func FunctionTotest(fo FloatOrder) { ... }
func TestAFunction(t *testing.T) {
FunctionToTest(testInts{1,2,3,4})
....
}
(Completely untested, illustration-only code)

Is there an easy way to iterate over a map in order?

This is a variant of the venerable "why is my map printing out of order" question.
I have a (fairly large) number of maps of the form map[MyKey]MyValue, where MyKey and MyValue are (usually) structs. I've got "less" functions for all the key types.
I need to iterate over the maps in order. (Specifically, the order defined by the less function on that type.) Right now, my code looks like this:
type PairKeyValue struct {
MyKey
MyValue
}
type PairKeyValueSlice []Pair
func (ps PairKeyValueSlice) Len() int {
return len(ps)
}
func (ps PairKeyValueSlice) Swap(i,j int) {
ps[i], ps[j] = ps[j], ps[i]
}
func (ps PairKeyValueSlice) Less(i,j int) {
return LessKey(ps[i].MyKey, ps[j].MyKey)
}
func NewPairKeyValueSlice(m map[MyKey]MyValue) (ps PairKeyValueSlice) {
ps = make(PairKeyValueSlice, len(m))
i := 0
for k,v := range m {
ps[i] = PairKeyValue{k,v}
i++
}
sort.Sort(ps)
}
And then, any time I want an in-order iteration, it looks like:
var m map[MyKey]MyValue
m = GetMapFromSomewhereUseful()
for _, kv := range NewPairKeyValueSlice(m) {
key := kv.MyKey
value := kv.MyValue
DoUsefulWork(key, value)
}
And this appears to largely work. The problem is that it is terribly verbose. Particularly since the problem at hand really has very little to do with implmenting ordered maps and is really about the useful work in the loop.
Also, I have several different keys and value types. So, every time I want to iterate over a map in order, I copy/paste all that code and do find/replace MyKey with the new key and MyValue with the new value. Copy/paste on that magnitude is... "smelly". It has already become a hassle, since I've already made a few errors that I had to fix several times.
This technique also has the downside that it requires making a full copy of all the keys and values. That is undesirable, but I don't see a way around it. (I could reduce it to just the keys, but it doesn't change the primary nature of the problem.)
This question is attempting the same thing with strings. This question does it with strings and ints. This question implies that you need to use reflection and will have to have a switch statement that switches on every possible type, including all user-defined types.
But with the people who are puzzled that maps don't iterate deterministically, it seems that there has got to be a better solution to this problem. I'm from an OO background, so I'm probably missing something fundamental.
So, is there a reasonable way to iterate over a map in order?
Update: Editing the question to have more information about the source, in case there's a better solution than this.
I have a lot of things I need to group for output. Each grouping level is in a structure that looks like these:
type ObjTypeTree struct {
Children map[Type]*ObjKindTree
TotalCount uint
}
type ObjKindTree struct {
Children map[Kind]*ObjAreaTree
TotalCount uint
}
type ObjAreaTree struct {
Children map[Area]*ObjAreaTree
TotalCount uint
Objs []*Obj
}
Then, I'd iterate over the children in the ObjTypeTree to print the Type groupings. For each of those, I iterate over the ObjKindTree to print the Kind groupings. The iterations are done with methods on the types, and each kind of type needs a little different way of printing its grouping level. Groups need to be printed in order, which causes the problem.
Don't use a map if key collating is required. Use a B-tree or any other/similar ordered container.
I second jnml's answer. But if you want something shorter than you have and are willing to give up compile time type safety, then my library might work for you. (It's built on top of reflect.) Here's a full working example:
package main
import (
"fmt"
"github.com/BurntSushi/ty/fun"
)
type OrderedKey struct {
L1 rune
L2 rune
}
func (k1 OrderedKey) Less(k2 OrderedKey) bool {
return k1.L1 < k2.L1 || (k1.L1 == k2.L1 && k1.L2 < k2.L2)
}
func main() {
m := map[OrderedKey]string{
OrderedKey{'b', 'a'}: "second",
OrderedKey{'x', 'y'}: "fourth",
OrderedKey{'x', 'x'}: "third",
OrderedKey{'a', 'b'}: "first",
OrderedKey{'x', 'z'}: "fifth",
}
for k, v := range m {
fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v)
}
fmt.Println("-----------------------------")
keys := fun.QuickSort(OrderedKey.Less, fun.Keys(m)).([]OrderedKey)
for _, k := range keys {
v := m[k]
fmt.Printf("(%c, %c): %s\n", k.L1, k.L2, v)
}
}
Note that such a method will be slower, so if you need performance, this is not a good choice.

Resources