I decided to create the quick sort algorithm in go.
My code for the quick sort is:
package sorting
func QuickSort(input []int) []int {
if len(input) <= 1 {
return input
}
sorted := input
pivotIndx := len(sorted) - 1 // The index of the last item of the array
pivot := sorted[pivotIndx] // The value of the last item in the array
curLowIndx := 0
for indx, val := range sorted {
if val < pivot {
// Swap the items
sorted[indx], sorted[curLowIndx] = sorted[curLowIndx], sorted[indx]
// Increment the index on which the low position is stored.
// We need to do this so that the next item that is lower can be stored/swapped with the correct position
curLowIndx = curLowIndx + 1
}
}
sorted[curLowIndx], sorted[pivotIndx] = sorted[pivotIndx], sorted[curLowIndx]
// Sort the sub-arrays
QuickSort(sorted[:curLowIndx])
QuickSort(sorted[curLowIndx+1:])
return sorted
}
Code for the main file:
package main
import (
"fmt"
"github.com/.../.../sorting"
)
func main() {
// Sorting examples
toSort := []int{100, 20, 70, 30, 90, 40, 120, 123, 10, 23}
fmt.Println(toSort) // returns: [100 20 70 30 90 40 120 123 10 23]
shouldBeSorted := sorting.QuickSort(toSort)
fmt.Println(shouldBeSorted) // returns: [10 20 23 30 40 70 90 100 120 123]
fmt.Println(toSort) // ALSO returns: [10 20 23 30 40 70 90 100 120 123]
}
In my main function I have a slice in a variable which I want to be sorted (toSort).
I create a new variable in which I want to store the sorted slice (shouldBeSorted).
But here I find something that I did not expect, nor understand.
When I call the sorting.QuickSort(toSort) it sorts it and also assigns the return value to the shouldBeSorted variable, but next to that it also updates the toSort variable with the result from sorting.QuickSort(toSort).
I have read about the usage of pointers in go and would expect this behavior when passing a pointer through, but not when passing a 'regular' variable.
So my actual question is: why does this happen? Why does it change the toSort variable? Is there something I did wrong or is this expected and why would this be expected?
Side note:
The same thing happens in the QuickSort function it self when the recursion happens:
QuickSort(sorted[:curLowIndx])
QuickSort(sorted[curLowIndx+1:])
I first though that I would need to combine the slices I would get back, but apparently it updates the original sorted slice.
Slices in go actually consist of a struct with meta info and a pointer to a contiguous memory location that stores the actual data. Even though you're passing toSort by value, the copied meta struct still refers to the same underlying memory location. That is why toSort gets changed as well.
If you do not want this to happen, you can use copy to create a new slice and pass it on.
Slice Internals: https://blog.golang.org/slices-intro
Copy: https://golang.org/pkg/builtin/#copy
Slices are just pointers to the underlying data so when you update the given parameter, you are changing the actual data. That's why you need to copy your data:
func copySlice(s []int) []int {
c := make([]int, len(s))
copy(c, s)
return c
}
func main() {
toSort := []int{100, 20, 70, 30, 90, 40, 120, 123, 10, 23}
sorted := sorting.QuickSort(copySlice(toSort))
fmt.Println(toSort)
fmt.Println(sorted)
}
Related
How can I implement RemoveRange method in golang? It is a method in C# as shown here
I want to implement RemoveRange method on my hashCode string array and return new modified array back if possible with those ranges remove.
func removeRange(hashCode []string, idx int, count int) []string {
var temp []string
for i, s := range hashCode {
fmt.Println(i, s)
// confuse here on what to do
}
return temp
}
Simply slice the slice up until idx, skip count elements and append the rest to the result of the first slicing:
func removeRange(hashCode []string, idx int, count int) []string {
return append(hashCode[:idx], hashCode[idx+count:]...)
}
Testing it:
s := []string{"0", "1", "2", "3", "4", "5"}
fmt.Println(s)
s = removeRange(s, 1, 2)
fmt.Println(s)
Which outputs (try it on the Go Playground):
[0 1 2 3 4 5]
[0 3 4 5]
Note: the above implementation does not check whether indices are valid (whether they are in range). If not, the code could panic. Add necessary checks if you need to.
Note #2: the above implementation modifies the elements of the passed slice, the returned slice will share the backing array of the parameter. If you want to avoid this, if you want to leave the input intact and allocate a new slice for the result, then do so:
func removeRange(hashCode []string, idx int, count int) []string {
result := make([]string, 0, len(hashCode)-count)
result = append(result, hashCode[:idx]...)
result = append(result, hashCode[idx+count:]...)
return result
}
Try this one on the Go Playground.
You don't need a method or function for this at all in golang. Go slices can be subsliced and appended in place, which is how you can quickly and easily remove subsets from any slice.
Say you want to remove 2 elements, starting at index 2, you'd simply write:
Sub := append(original [:2], original [4:]...)
Demo
How this works:
original[:2] creates a sub-slice starting at 0, with a length of 2 elements (so index 0 and 1)
append because to this first part, we want to add the rest of the slice, minus the range we want to skip/remove
original[4:] creates another sub-slice, this time starting at index 4, and ending wherever original ends. Just like we don't explicitly mention 0 as the starting point in the first sub-slice, by not specifying a number of elements here, golang will just include all of the remaining elements in the slice.
... because append is a variadic function (built-in, but you get the point), we need to pass in every element we want to append as a new argument. The ... operator expands the sub-slice and passes in every element as a separate argument.
Because we assigned the new slice to a new variable, original will remain unchanged, so if you want to overwrite the slice, you just assign it to the same variable.
Note I wrote this on my phone, so markup and code may not be quite right, but this should answer your question at least
I've explained the code using // comments and if not commented, code is self explanatory.
package main
import (
"fmt"
"os"
)
func RemoveRange(s []string, index, count int) []string {
sLen := len(s)
// Similar semantics to match (similar) the behavior of
// C# implementation
switch {
case index < 0, count < 0: // arguments are not valid
fmt.Fprintln(os.Stderr, "error: argument out of range error")
return s
case index+count-1 >= sLen: // range results in exceeding the limit
fmt.Fprintln(os.Stderr, "error: argument error")
return s
}
// Create a slice p and pre-allocate the size required
// to store the resultant slice after removing range.
// Result := s[:] -> s[:index] + s[index+count:]
// Remove := s[index:index+count-1]
p := make([]string, 0, sLen-count)
p = append(p, s[:index]...)
p = append(p, s[index+count:]...)
return p
}
func main() {
s := []string{"0", "1", "2", "3", "4", "5"}
fmt.Println(s)
r := RemoveRange(s, 1, 3)
fmt.Println(r)
}
Output:
[0 1 2 3 4 5]
[0 4 5]
Probably just because I'm new to Go, but using the range syntax over arrays of structs doesn't behave as I'd expect. I'm assuming the array item gets copied to the range index, but the copy isn't a deep copy ... so the following is a little weird. Is this behaviour documented somewhere
package main
import "fmt"
type Inner struct {
x, y int
}
type Attr struct {
a int
inside []Inner
}
var item = []Attr{
{a: 1, inside: []Inner{{2, 3}, {3, 4}}},
{a: 2, inside: []Inner{{3, 4}, {1, 2}}},
}
func main() {
fmt.Println(item)
for _,i := range item {
// A: The following has no impact on item[].a
i.a = 111
// B: But this does ... why?
i.inside[0].x = 111
}
fmt.Println(item)
for j,_ := range item {
item[j].a = 333
item[j].inside[0].x = 333
}
fmt.Println(item)
}
In the loop for _, i := range item, each i is a copy of the corresponding slice element. Suppose, you write:
i := item[0]
i.a = 111
this does not change the original element of the slice, but only its copy. However in:
i.inside[0].x = 111
inside is a slice, i.e. only a thin wrapper referring to the underlying array, which is not copied on assignment. So with i.inside you deal with the same slice as items[0].inside.
More about slices internals.
The below code snippet confused me:
v, ok := a[1] // error: assignment count mismatch: 2 = 1
The above code throws an error because of count mismatch, but the below code snippet seems to work fine:
for i, id:= range ids
{
fmt.Printf("%d - ID: %d\n",i,id)
}
Does this mean that the range returns both the index and the value due to which the code snippet above works fine?
The range form of the for loop iterates over a slice or map.
When ranging over a slice, two values are returned for each iteration:
The first is the index of the slice;
The second is a copy of the element at that index.
Let's assume that we have a function that verify if a number is a prime number, and we have an array with the candidate numbers, than we can call the function in two different way:
var prime []int = []int{2, 3, 5, 7, 11, 13, 17, 19, 23}
func TestIsPrimeByValue(t *testing.T) {
for _, item := range prime {
if !IsPrime(item) {
t.Fail()
}
}
}
func TestIsPrimeByIndex(t *testing.T) {
for i := range prime {
if !IsPrime(prime[i]) {
t.Fail()
}
}
}
With the first loop, we are iterating the value of the array.
With the second loop, we are iterating the index of the array.
So I am trying to write a method that takes two slices, flips both of them and then gives them to each other.
Ex.
s1 = {1,2,3,4,5}
s2 = {6,7,8,9,10}
Should return:
s1 = {10,9,8,7,6}
s2 = {5,4,3,2,1}
Here is my code:
package main
import(
"fmt"
)
func main(){
f:= [5]int{1,2,3,4,5}
h:= [5]int{6,7,8,9,10}
var sliceF []int = f[0:5]
var sliceH []int = h[0:5]
fmt.Println(reverseReverse(sliceF,sliceH))
}
func reverseReverse(first []int, second []int) ([]int, []int){
//creating temp arrays to hold the traversed arrays before swapping.
var tempArr1 []int = first
var tempArr2 []int = second
//count is used for counting up the tempArrays in the correct order in the For loops
var count int= 0
//goes through the first array and sets the values starting from the end equal to the temp array
//which increases normally from left to right.
for i :=len(first)-1; i>=0;i--{
tempArr1[count] = first[i]
fmt.Println(i)
count++
}
count =0
//same as first for loop just on the second array
for i :=len(second)-1; i>=0;i--{
tempArr2[count] = second[i]
count++
}
//trying to replace the values of the param arrays to be equal to the temp arrays
first=tempArr2
second = tempArr1
//returning the arrays
return first,second
}
When run here is the output:
4
3
2
1
0
[10 9 8 9 10]
[5 4 3 4 5]
*Not I included a print statement in the for loop to check if the index is decreasing properly.
I understand there are better ways to do this but for proof of concept I want to use a for loop.
Any help appreciated. I am new to go and tend to have java habits so I assume somehow my problem is related to that.
This can be done much simpler by realizing there's no need to actually swap the individual elements. Instead, reverse each array and swap their order. Much simpler!
func reverseReverse( a, b []int ) ([]int, []int) {
return reverse(b), reverse(a)
}
func reverse( a []int ) []int {
end := len(a) - 1
// Allocate a new array slice of the same length to copy to.
ret := make( []int, len(a) )
// Copy each element of a into ret, reversed.
for i := range a {
ret[end-i] = a[i]
}
return ret
}
With that revelation, there's little need for the very specialized reverseReverse function. Swap the order yourself.
fmt.Println(reverse(sliceH), reverse(sliceF))
Note that if you just want to take a slice of an array, it's sufficient to write sliceH []int := h[:] without specifying the start and end. The start is assumed to be 0 and the end is the end. Also note there's no need to declare the type, := takes care of that for you.
Even better, you can declare and initialize them directly.
sliceF:= []int{1,2,3,4,5}
sliceH:= []int{6,7,8,9,10}
Short answer:
tempArr1[count] = first[i]
This line is logically identical to:
first[count] = first[i]
Detailed answer:
x := [5]int{} and x := []int{} are in fact two very different assignments. In the first case x is actually a static array. In the second case x is a slice which is in fact a data structure which has a length, capacity and a pointer to the underlying array. Therefore, var tempArr1 []int = first means copy the pointer to the underlying array of first into the tempArr1, so any modification to first[i] will be reflected in tempArr1 and vice versa
For example,
package main
import "fmt"
func reverse(s []int) []int {
for i := 0; i < len(s)/2; i++ {
s[i], s[len(s)-1-i] = s[len(s)-1-i], s[i]
}
return s
}
func main() {
s1, s2 := []int{1, 2, 3, 4, 5}, []int{6, 7, 8, 9, 10}
fmt.Println(s1, s2)
s1, s2 = reverse(s2), reverse(s1)
fmt.Println(s1, s2)
}
Output:
[1 2 3 4 5] [6 7 8 9 10]
[10 9 8 7 6] [5 4 3 2 1]
I wanted to implement time based slots for holding data using golang slices. I managed to come up with a go program like this and it also works. But I have few questions regarding garbage collection and the general performance of this program. Does this program guarantee garbage collection of items once slice is equated to nil? And while shuffling slices, I hope this program does not do any deep copying.
type DataSlots struct {
slotDuration int //in milliseconds
slots [][]interface{}
totalDuration int //in milliseconds
}
func New(slotDur int, totalDur int) *DataSlots {
dat := &DataSlots{slotDuration: slotDur,
totalDuration: totalDur}
n := totalDur / slotDur
dat.slots = make([][]interface{}, n)
for i := 0; i < n; i++ {
dat.slots[i] = make([]interface{}, 0)
}
go dat.manageSlots()
return dat
}
func (self *DataSlots) addData(data interface{}) {
self.slots[0] = append(self.slots[0], data)
}
// This should be a go routine
func (self *DataSlots) manageSlots() {
n := self.totalDuration / self.slotDuration
for {
time.Sleep(time.Duration(self.slotDuration) * time.Millisecond)
for i := n - 1; i > 0; i-- {
self.slots[i] = self.slots[i-1]
}
self.slots[0] = nil
}
}
I removed critical section handling in this snippet to make it concise.
Once your slice is set too nil, any values contained in the slice are available for garbage collection, provided that the underlying array isn't shared with another slice.
Since there are no slice operations in your program, you never have multiple references to the same array, nor are you leaving data in any inaccessible portions of the underlying array.
What you need to be careful of, is when you're using slice operations:
a := []int{1, 2, 3, 4}
b := a[1:3]
a = nil
// the values 1 and 4 can't be collected, because they are
// still contained in b's underlying array
c := []int{1, 2, 3, 4}
c = append(c[1:2], 5)
// c is now []int{2, 5}, but again the values 1 and 4 are
// still in the underlying array. The 4 may be overwritten
// by a later append, but the 1 is inaccessible and won't
// be collected until the underlying array is copied.
While append does copy values when the capacity of the slice in insufficient, only the values contained in the slice are copied. There is no deep copy of any of the values.