Flipping a slice with a for loop logic error - go

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]

Related

How to get rid of zero value in a int slice in Go?

I am trying to find even numbers in a list of numbers, here is my attempt:
package main
import "fmt"
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7}
res := []int{}
for n := range nums {
if n%2 == 0 {
res = append(res, n)
}
}
fmt.Println(res)
}
It seems straightforward; however, when I run the program, I got the result
[0 2 4 6]
Where does the zero come from? It must be from the empty slice res. How can I get rid of this zero?
for n := range nums {
// ...
}
n is not the elements of the nums slice, it is the index. So basically you tested and added the indices of the elements to your res result slice.
Instead do this:
for _, n := range nums {
// ...
}
With this change, output will be (try it on the Go Playground):
[2 4 6]
This is detailed in Spec: For statements, For statements with range clause:
For each iteration, iteration values are produced as follows if the respective iteration variables are present:
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E

big.Int slice rewriting itself on append()

I am trying to get a slice of big.Ints of the odd numbers between 3 and the square root of i.
When I run the following code:
import (
"fmt"
"math/big"
)
func main() {
i := big.NewInt(101)
var divisorsOfPrime []*big.Int
squareRoot := big.NewInt(0).Sqrt(i)
for n := big.NewInt(3); n.Cmp(squareRoot) == -1; n.Add(n, big.NewInt(2)) {
divisorsOfPrime = append(divisorsOfPrime, n)
}
fmt.Println(divisorsOfPrime)
}
I get the output:
[11 11 11 11]
But I expect the output:
[3 5 7 9 11]
What can I do to fix this?
Thanks
You have a slice of *big.Int in which you store the same pointer over and over again.
Instead, you need to store a copy of n on each iteration.
Replace:
divisorsOfPrime = append(divisorsOfPrime, n)
With:
nCopy := new(big.Int).Set(n)
divisorsOfPrime = append(divisorsOfPrime, nCopy)
By the way, this is not specific to *big.Int; as long as you're handling pointers you need to create new objects and store pointers to those new objects, not the original one. Notice that n is assigned exactly once.

Golang: Problems when using append on slice

I am using golang. Here is my code:
func main() {
quanPailie([]int{1, 2})
}
func quanPailie(nums []int) [][]int {
COUNT := len(nums)
//only one item
if COUNT == 1 {
return [][]int{nums}
}
insertItem(quanPailie(nums[:COUNT-1]), nums[COUNT-1])
return [][]int{}
}
func insertItem(res [][]int, insertNum int) {
fmt.Println("insertItem,res:", res, "insertNum", insertNum) //insertItem,res: [[1]] insertNum 2
for _, v := range res {
for i := 0; i < len(v); i++ {
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
fmt.Println("ccc", c)
}
}
}
What makes me very confused is the output:
===before,v: [1]
===after,v: [2]
Why did the value of v change? Hope someone can help me. Thanks a lot.
Go playground: https://play.golang.org/p/wITYsGpX7U
EDIT:
Thanks for icza's great help, I think I have understood this problem.
And, here is a simple code to show this issue.
func test1() {
nums := []int{1, 2, 3}
_ = append(nums[:2], 4)
fmt.Println("test1:", nums)
//nums changes because the cap is big enought, the original array is modified.
}
func test2() {
nums := []int{1, 2, 3}
c := append(nums[:2], []int{4, 5, 6}...)
fmt.Println("test2:", nums)
fmt.Println("cc:", c)
//nums dont't change because the cap isn't big enought.
//a new array is allocated while the nums still points to the old array.
//Of course, the return value of append points to the new array.
}
Go playground: https://play.golang.org/p/jBNFsCqUn3
This is the code in question:
fmt.Println("===before,v:", v)
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v)
You ask why v changes between the 2 Println() statements.
Because you are using the builtin append() function, quoting from its doc:
The append built-in function appends elements to the end of a slice. If it has sufficient capacity, the destination is resliced to accommodate the new elements. If it does not, a new underlying array will be allocated. Append returns the updated slice.
So if the slice you append to has enough room (capacity) to accomodate the elements you want to append, no new slice will be allocated, instead the destination slice will be re-sliced (which will use the same underlying array) and append will happen in that.
Let's check the capacity:
fmt.Println("===before,v:", v, cap(v))
c := append(v[:i], append([]int{insertNum}, v[i:]...)...)
fmt.Println("===after,v:", v, cap(v))
Output:
===before,v: [1] 2
===after,v: [2] 2
The v slice has a capacity of 2. When for loop starts, i=0, v[:i] is v[:0] which is an empty slice (but has capacity 2) and so appending 1 or 2 elements will not allocate a new array/slice, it will be done "in place". This "in place" is the 0th element of v, since v[:i] is shorthand for v[0:i]. Hence the elements will be appended starting from v[0] in the underlying array which is shared, so the element denoted by v[0] will change.
Note that slicing a slice results in a slice which shares its underlying backing array with the original slice (does not make a copy of the elements).
If you want to avoid this, use or allocate a new slice, copy original content and append to the new slice, e.g.:
src := []int{1, 2}
c := make([]int, len(src))
copy(c, src)
// Append something:
c = append(c, 3, 4)
fmt.Println(src) // [1 2] - src doesn't change
fmt.Println(c) // [1 2 3 4]

golang: sort.Search can't find first element in a slice

I have write some code to find element position in sorted slice use sort.Search, but it can't correctly get the right position of first element.
package main
import (
"fmt"
"sort"
)
func main() {
data := []int{1, 2, 3}
fmt.Println(sort.Search(len(data), func(i int) bool {
return data[i] < 2 // or data[i] == 1
}))
}
The standard output is always 3 rather than 0.
Is it a bug? Or am i wrong?
Thanks.
If you want to search for the first element, then in your comparator function you should compare the ith element to the first which is data[0] (or the value which is 1).
And since your slice is sorted in ascending order, you have to use the >= operator for comparision because sort.Search() returns the smallest index i in [0, n) at which f(i) is true.
data := []int{1, 2, 3}
fmt.Println(sort.Search(len(data), func(i int) bool {
return data[i] >= data[0] // You could also use 1 instead of data[0]
}))
Output: 0 as expected. Try it on Go Playground.

How do I reverse an array in Go?

http://play.golang.org/p/W70J4GU7nA
s := []int{5, 2, 6, 3, 1, 4}
sort.Reverse(sort.IntSlice(s))
fmt.Println(s)
// 5, 2, 6, 3, 1, 4
It is hard to understand what it means in func Reverse(data Interface) Interface .
How do I reverse an array? I do not need to sort.
Honestly this one is simple enough that I'd just write it out like this:
package main
import "fmt"
func main() {
s := []int{5, 2, 6, 3, 1, 4}
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
fmt.Println(s)
}
http://play.golang.org/p/vkJg_D1yUb
(The other answers do a good job of explaining sort.Interface and how to use it; so I won't repeat that.)
Normally, to sort an array of integers you wrap them in an IntSlice, which defines the methods Len, Less, and Swap. These methods are in turn used by sort.Sort. What sort.Reverse does is that it takes an existing type that defines Len, Less, and Swap, but it replaces the Less method with a new one that is always the inverse of the underlying Less:
type reverse struct {
// This embedded Interface permits Reverse to use the methods of
// another Interface implementation.
Interface
}
// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
return r.Interface.Less(j, i)
}
// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
return &reverse{data}
}
So when you write sort.Reverse(sort.IntSlice(s)), whats happening is that you're getting this new, 'modified' IntSlice that has it's Less method replaced. So if you call sort.Sort on it, which calls Less, it will get sorted in decreasing order.
I'm 2 years late, but just for fun and interest I'd like to contribute an "oddball" solution.
Assuming the task really is to reverse a list, then for raw performance bgp's solution is probably unbeatable. It gets the job done simply and effectively by swapping array items front to back, an operation that's efficient in the random-access structure of arrays and slices.
In Functional Programming languages, the idiomatic approach would often involve recursion. This looks a bit strange in Go and will have atrocious performance. That said, here's a recursive array reversal function (in a little test program):
package main
import (
"fmt"
)
func main() {
myInts := []int{ 8, 6, 7, 5, 3, 0, 9 }
fmt.Printf("Ints %v reversed: %v\n", myInts, reverseInts(myInts))
}
func reverseInts(input []int) []int {
if len(input) == 0 {
return input
}
return append(reverseInts(input[1:]), input[0])
}
Output:
Ints [8 6 7 5 3 0 9] reversed: [9 0 3 5 7 6 8]
Again, this is for fun and not production. Not only is it slow, but it will overflow the stack if the list is too large. I just tested, and it will reverse a list of 1 million ints but crashes on 10 million.
First of all, if you want to reverse the array, do like this,
for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
a[i], a[j] = a[j], a[i]
}
Then, look at the usage of Reverse in golang.org
package main
import (
"fmt"
"sort"
)
func main() {
s := []int{5, 2, 6, 3, 1, 4} // unsorted
sort.Sort(sort.Reverse(sort.IntSlice(s)))
fmt.Println(s)
}
// output
// [6 5 4 3 2 1]
And look at the description of Reverse and Sort
func Reverse(data Interface) Interface
func Sort(data Interface)
Sort sorts data. It makes one call to data.Len to determine n, and O(n*log(n)) calls to data.Less and data.Swap. The sort is not guaranteed to be stable.
So, as you know, Sort is not just a sort algorithm, you can view it as a factory, when you use Reverse it just return a reversed sort algorithm, Sort is just doing the sorting.
This is a more generic slice reverse function. It will panic if input is not a slice.
//panic if s is not a slice
func ReverseSlice(s interface{}) {
size := reflect.ValueOf(s).Len()
swap := reflect.Swapper(s)
for i, j := 0, size-1; i < j; i, j = i+1, j-1 {
swap(i, j)
}
}
If you want to reverse the array, you can just go through it in reverse order. Since there is no "reverse range" primitive in the language (at least not yet), you must do something like this (http://play.golang.org/p/AhvAfMjs_7):
s := []int{5, 2, 6, 3, 1, 4}
for i := len(s) - 1; i >= 0; i-- {
fmt.Print(s[i])
if i > 0 {
fmt.Print(", ")
}
}
fmt.Println()
Regarding whether it is hard to understand what sort.Reverse(data Interface) Interface does, I thought the same until I saw the source code from "http://golang.org/src/pkg/sort/sort.go".
It just makes the comparisons required for the sorting to be made "the other way around".
Here is a simple Go solution that uses an efficient (no extra memory) approach to reverse an array:
i := 0
j := len(nums) - 1
for i < j {
nums[i], nums[j] = nums[j], nums[i]
i++
j--
}
The idea is that reversing an array is equivalent to swapping each element with its mirror image across the center.
https://play.golang.org/p/kLFpom4LH0g
Here is another way to do it
func main() {
example := []int{1, 25, 3, 5, 4}
sort.SliceStable(example, func(i, j int) bool {
return true
})
fmt.Println(example)
}
https://play.golang.org/p/-tIzPX2Ds9z
func Reverse(data Interface) Interface
This means that it takes a sort.Interface and returns another sort.Interface -- it doesn't actually doing any sorting itself. For example, if you pass in sort.IntSlice (which is essentially a []int that can be passed to sort.Sort to sort it in ascending order) you'll get a new sort.Interface which sorts the ints in descending order instead.
By the way, if you click on the function name in the documentation, it links directly to the source for Reverse. As you can see, it just wraps the sort.Interface that you pass in, so the value returned from Reverse gets all the methods of the original sort.Interface. The only method that's different is the Less method which returns the opposite of the Less method on the embedded sort.Interface. See this part of the language spec for details on embedded fields.
From Golang wiki SliceTricks:
To replace the contents of a slice with the same elements but in
reverse order:
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}
The same thing, except with two indices:
for left, right := 0, len(a)-1; left < right; left, right = left+1, right-1 {
a[left], a[right] = a[right], a[left]
}
To reverse an array in place, iterate to its mid-point, and swap each element with its "mirror element":
func main() {
xs := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
itemCount := len(xs)
for i := 0; i < itemCount/2; i++ {
mirrorIdx := itemCount - i -1
xs[i], xs[mirrorIdx] = xs[mirrorIdx], xs[i]
}
fmt.Printf("xs: %v\n", xs)
}
https://play.golang.org/p/JeSApt80_k
Here is a method using append:
package main
import "fmt"
func main() {
a := []int{10, 20, 30, 40, 50}
for n := len(a) - 2; n >= 0; n-- {
a = append(a[:n], append(a[n + 1:], a[n])...)
}
fmt.Println(a)
}
Drawing of the steps:
10 20 30 40 50
10 20 30 50 40
10 20 50 40 30
10 50 40 30 20
50 40 30 20 10
This answer is mainly for those beginners who wish to write this code using only one variable in the for loop instead of using two variables (like i & j).
package main
import "fmt"
func main() {
array := []int{45, 17, 43, 67, 21, 4, 97, 44, 54, 98, 665}
fmt.Println("initial array:", array)
loop_iteration := len(array)
if len(array)%2 == 0 {
loop_iteration = (len(array) / 2) - 1
} else {
loop_iteration = int(len(array) / 2) //This will give the lower integer value of that float number.
}
for i := 0; i <= loop_iteration; i++ {
array[i], array[(len(array)-1)-i] = array[(len(array)-1)-i], array[i]
}
fmt.Println("reverse array:", array)
}
https://go.dev/play/p/bVp0x7v6Kbs
package main
import (
"fmt"
)
func main() {
arr := []int{1, 2, 3, 4, 5}
fmt.Println(reverseArray(arr))
}
func reverseArray(arr []int) []int {
reversed := make([]int, len(arr))
j := 0
for i := len(arr) - 1; i >= 0; i-- {
reversed[j] = arr[i]
j++
}
return reversed
}
Simple solution without involving math. Like this solution, this is inefficient as it does too much allocation and garbage collection. Good for non-critical code where clarity is more important than performance. Playground: https://go.dev/play/p/dQGwrc0Q9ZA
arr := []int{1, 3, 4, 5, 6}
var rev []int
for _, n := range arr {
rev = append([]int{n}, rev...)
}
fmt.Println(arr)
fmt.Println(rev)
Its very simple if you want to print reverse array
Use Index from length doing i--
ex.
a := []int{5, 4, 12, 7, 15, 9}
for i := 0; i <= len(a)-1; i++ {
fmt.Println(a[len(a)-(i+1)])
}
https://go.dev/play/p/bmyFh7-_VCZ
Here is my solution.
package main
import (
"fmt"
)
func main() {
var numbers = [10]int {1,2,3,4,5,6,7,8,9,10}
var reverseNumbers [10]int
j:=0
for i:=len(numbers)-1; i>=0 ; i-- {
reverseNumbers[j]=numbers[i]
j++
}
fmt.Println(reverseNumbers)
}
Here is my solution to reversing an array:
func reverse_array(array []string) []string {
lenx := len(array) // lenx holds the original array length
reversed_array := make([]string, lenx) // creates a slice that refer to a new array of length lenx
for i := 0; i < lenx; i++ {
j := lenx - (i + 1) // j initially holds (lenx - 1) and decreases to 0 while i initially holds 0 and increase to (lenx - 1)
reversed_array[i] = array[j]
}
return reversed_array
}
You can try this solution on the go playground the go playground
package main
import "fmt"
func main() {
array := []string{"a", "b", "c", "d"}
fmt.Println(reverse_array(array)) // prints [d c b a]
}
Do not reverse it, leave it as now and then just iterate it backwards.

Resources