Golang remove dup ints from slice append function "evaluated but not used" - go

I can't get this Go lang test program to run. The compiler keeps giving an error on the append() function call below with an "evaluated but not used" error. I can't figure out why.
package main
import (
"fmt"
)
func removeDuplicates(testArr *[]int) int {
prevValue := (*testArr)[0]
for curIndex := 1; curIndex < len((*testArr)); curIndex++ {
curValue := (*testArr)[curIndex]
if curValue == prevValue {
append((*testArr)[:curIndex], (*testArr)[curIndex+1:]...)
}
prevValue = curValue
}
return len(*testArr)
}
func main() {
testArr := []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}
nonDupSize := removeDuplicates(&testArr)
fmt.Printf("nonDupSize = %d", nonDupSize)
}

"evaluated but not used" error.
Code below is my idea. I think your code is not very clear.
package main
import (
"fmt"
)
func removeDuplicates(testArr *[]int) int {
m := make(map[int]bool)
arr := make([]int, 0)
for curIndex := 0; curIndex < len((*testArr)); curIndex++ {
curValue := (*testArr)[curIndex]
if has :=m[curValue]; !has {
m[curValue] = true
arr = append(arr, curValue)
}
}
*testArr = arr
return len(*testArr)
}
func main() {
testArr := []int{0, 0, 1, 1, 1, 2, 2, 3, 3, 4}
nonDupSize := removeDuplicates(&testArr)
fmt.Printf("nonDupSize = %d", nonDupSize)
}

Peter's answer nailed it, the compile error was due to not grabbing the return value from append()

Related

Is Golang's ... syntax really just varargs?

Well, I have a simple example, although it may seem pointless, but these examples have deviated greatly from my cognition.
Can anyone tell me what happened.
I pass the elements in []int to the parameter args with the ... syntax, but when I change the formal parameter args, the []int actual parameter is changed.
I modified the ordering of args , but the ordering of []int is also affected:
package main
import (
"fmt"
)
func bubbleSort(args ...int) {
for i := 0; i < len(args); i++ {
for j := 0; j < len(args)-1; j++ {
if args[j] > args[j+1] {
args[j], args[j+1] = args[j+1], args[j]
}
}
}
}
func main() {
isle := []int{3, 6, 1, 2, 5}
bubbleSort(isle...)
fmt.Printf("%v\n", isle)
}
// [1 2 3 5 6]
What if I pass in a single parameter? Apparently []int is not affected by args:
package main
import (
"fmt"
)
func bubbleSort(args ...int) {
for i := 0; i < len(args); i++ {
for j := 0; j < len(args)-1; j++ {
if args[j] > args[j+1] {
args[j], args[j+1] = args[j+1], args[j]
}
}
}
}
func main() {
isle := []int{3, 6, 1, 2, 5}
bubbleSort(isle[0], isle[1], isle[2], isle[3], isle[4])
fmt.Printf("%v\n", isle)
}
// [3 6 1 2 5]
Golang is not about "variable safety" as Rust. So you shoud never think that slice sent to function will not be corrupted.
If you want to use variadic functions but send slices, copy it:
func myUnsafeFunc(args ...int) {
// it will change args
}
func wantToSaveSliceFunc() {
myLovingSlice := []int{1,2,3}
myUnsafeFunc(append([]int(nil), slice...)...)
}
https://freshman.tech/snippets/go/copy-slices/
It's not confusing if you remember that spread operator ... is just a shugar .
Do not use it in your own API without serious reasone (as in fmt.Printf(...) for example) prefer use of explicit x []type notation over x ...type:
func myUnsafeFunc(args []int) {
// it will change args
}
func wantToSaveSliceFunc() {
myLovingSlice := []int{1,2,3}
myUnsafeFunc(append([]int(nil), slice...))
}
it still requires copying of slice, but it's much clear by semantics

Translate numpy digitize function into go

Digitize function return the indices of the bins to which each value in input array belongs.
Below code is from python -
x = np.array([0.8, 6.9, 3.5, 1.9])
bins = np.array([0.0, 1.0, 2.5, 4.0, 10.0])
inds = np.digitize(x, bins)
print(inds)
array([1, 4, 3, 2])
This does it:
package main
import (
"fmt"
"sort"
)
func digitize(x, bins []float64) []int {
inds := make([]int, len(x))
for k, v := range x {
inds[k] = sort.SearchFloat64s(bins, v)
}
return inds
}
func main() {
x := []float64{0.8, 6.9, 3.5, 1.9}
bins := []float64{0, 1, 2.5, 4, 10}
inds := digitize(x, bins)
fmt.Println(inds) // [1 4 3 2]
}
https://golang.org/pkg/sort#SearchFloat64s
package main
import (
"errors"
"fmt"
"sort"
)
type arr []float64
func (a arr) Less(i, j int) bool {
return a[i] < a[j]
}
func (in arr) digitize(bins arr) ([]int, error) {
if !sort.SliceIsSorted(bins, bins.Less) {
return nil, errors.New("bins array is not sorted")
}
indices := make([]int, len(in))
for i, x := range in {
indices[i] = sort.SearchFloat64s(bins, x)
}
return indices, nil
}
func main() {
var (
x = arr{0.8, 6.9, 3.5, 1.9}
bins = arr{0.0, 1.0, 2.5, 4.0, 10.0}
)
indices, err := x.digitize(bins)
if err != nil {
panic(err)
}
fmt.Println(indices)
}
Ref: https://golang.org/pkg/sort#SearchFloat64s
SearchFloat64s searches for x in a sorted slice of float64s and returns the index as specified by Search. The return value is the index to insert x if x is not present (it could be len(a)). The slice must be sorted in ascending order.

Change slice content and capacity inside a function in-place

I am trying to learn Go, so here is my very simple function for removing adjacent duplicates from slice for exercise from the book by Donovan & Kernighan.
Here is the code: https://play.golang.org/p/avHc1ixfck
package main
import "fmt"
func main() {
a := []int{0, 1, 1, 3, 3, 3}
removeDup(a)
fmt.Println(a)
}
func removeDup(s []int) {
n := len(s)
tmp := make([]int, 0, n)
tmp = append(tmp, s[0])
j := 1
for i := 1; i < n; i++ {
if s[i] != s[i-1] {
tmp = append(tmp, s[i])
j++
}
}
s = s[:len(tmp)]
copy(s, tmp)
}
It should print out [0 1 3] - and I checked, actually tmp at the end of the function it has desired form. However, the result is [0 1 3 3 3 3]. I guess there is something with copy function.
Can I somehow replace input slice s with the temp or trim it to desired length?
Option 1
Return a new slice as suggested by #zerkms.
https://play.golang.org/p/uGJiD3WApS
package main
import "fmt"
func main() {
a := []int{0, 1, 1, 3, 3, 3}
a = removeDup(a)
fmt.Println(a)
}
func removeDup(s []int) []int {
n := len(s)
tmp := make([]int, 0, n)
tmp = append(tmp, s[0])
for i := 1; i < n; i++ {
if s[i] != s[i-1] {
tmp = append(tmp, s[i])
}
}
return tmp
}
Option 2
Use pointers for pass-by-reference.
The same thing in effect as that of option1.
https://play.golang.org/p/80bE5Qkuuj
package main
import "fmt"
func main() {
a := []int{0, 1, 1, 3, 3, 3}
removeDup(&a)
fmt.Println(a)
}
func removeDup(sp *[]int) {
s := *sp
n := len(s)
tmp := make([]int, 0, n)
tmp = append(tmp, s[0])
for i := 1; i < n; i++ {
if s[i] != s[i-1] {
tmp = append(tmp, s[i])
}
}
*sp = tmp
}
Also, refer to following SO thread:
Does Go have no real way to shrink a slice? Is that an issue?
Here's two more slightly different ways to achieve what you want using sets and named types. The cool thing about named types is that you can create interfaces around them and can help with the readability of lots of code.
package main
import "fmt"
func main() {
// returning a list
a := []int{0, 1, 1, 3, 3, 3}
clean := removeDup(a)
fmt.Println(clean)
// creating and using a named type
nA := &newArrType{0, 1, 1, 3, 3, 3}
nA.removeDup2()
fmt.Println(nA)
// or... casting your orginal array to the named type
nB := newArrType(a)
nB.removeDup2()
fmt.Println(nB)
}
// using a set
// order is not kept, but a set is returned
func removeDup(s []int) (newArr []int) {
set := make(map[int]struct{})
for _, n := range s {
set[n] = struct{}{}
}
newArr = make([]int, 0, len(set))
for k := range set {
newArr = append(newArr, k)
}
return
}
// using named a typed
type newArrType []int
func (a *newArrType) removeDup2() {
x := *a
for i := range x {
f := i + 1
if f < len(x) {
if x[i] == x[f] {
x = x[:f+copy(x[f:], x[f+1:])]
}
}
}
// check the last 2 indexes
if x[len(x)-2] == x[len(x)-1] {
x = x[:len(x)-1+copy(x[len(x)-1:], x[len(x)-1+1:])]
}
*a = x
}

How to find an element intersect in other array

I have an array like:
a:= [1,2,3,4,5]
b:= [5,6,7,8,9]
How to know array b have contain element in array a without using foreach?
How to know array b have contain element in array a without using foreach?
You can't. And you should not try as this is pointless restriction.
If the arrays are sorted (as they appear to be in your question) there is an algorithm that works better than going through each element.
Pick the first element of a, call it x.
Binary search b for the first element equal or greater than x. If they are equal, you found an element that is contained in both arrays, if not, make that your new x. Now search a for x in the same way. Repeat until you run out of elements in one of the arrays.
This can be trivially extended to an arbitrary number of arrays (in fact, it's easier to write with an arbitrary number of arrays).
Here's a quick and dirty implementation:
package main
import (
"fmt"
"sort"
)
func inter(arrs ...[]int) []int {
res := []int{}
x := arrs[0][0]
i := 1
for {
off := sort.SearchInts(arrs[i], x)
if off == len(arrs[i]) {
// we emptied one slice, we're done.
break
}
if arrs[i][off] == x {
i++
if i == len(arrs) {
// x was in all the slices
res = append(res, x)
x++ // search for the next possible x.
i = 0
}
} else {
x = arrs[i][off]
i = 0 // This can be done a bit more optimally.
}
}
return res
}
func main() {
a := []int{1, 2, 3, 4, 5, 7}
b := []int{5, 6, 7, 8, 9}
fmt.Println(inter(a, b))
}
package main
import (
set "github.com/deckarep/golang-set"
)
func array_intersect(a, b []interface{}) []interface{} {
return set.NewSetFromSlice(a).Intersect(set.NewSetFromSlice(b)).ToSlice()
}
func main() {
a := []interface{}{1, 2, 3, 4, 5, 7}
b := []interface{}{5, 6, 7, 8, 9}
println(array_intersect(a, b))
}
package main
import (
"fmt"
"sort"
)
func array_intersect(a, b []int) []int {
ret := []int{}
lenA := len(a)
lenB := len(b)
if lenA == 0 || lenB == 0 {
return ret
}
sort.Ints(a)
sort.Ints(b)
var i, j int
for {
a = a[i:]
if i = sort.SearchInts(a, b[j]); i >= len(a) {
break
}
if a[i] == b[j] {
ret = append(ret, a[i])
}
if j++; j >= lenB {
break
}
}
return ret
}
func main() {
a := []int{5, 7, 1, 1, 2, 3, 4, 5, 7}
b := []int{1, 1, 5, 6, 7, 8, 9}
fmt.Printf("a=%v, b=%v", a, b)
fmt.Printf("%v\n", array_intersect(a, b))
fmt.Printf("a=%v, b=%v", a, b)
}

Is there a way to iterate over a slice in reverse in Go?

It would be convenient to be able to say something like:
for _, element := reverse range mySlice {
...
}
Edit: I asked this question a long time ago, it is 2022 now and the generic solution by #Ivan below seems like the way to go!
No there is no convenient operator for this to add to the range one in place. You'll have to do a normal for loop counting down:
s := []int{5, 4, 3, 2, 1}
for i := len(s)-1; i >= 0; i-- {
fmt.Println(s[i])
}
You can also do:
s := []int{5, 4, 3, 2, 1}
for i := range s {
fmt.Println(s[len(s)-1-i]) // Suggestion: do `last := len(s)-1` before the loop
}
Output:
1
2
3
4
5
Also here: http://play.golang.org/p/l7Z69TV7Vl
Variation with index
for k := range s {
k = len(s) - 1 - k
// now k starts from the end
}
How about use defer:
s := []int{5, 4, 3, 2, 1}
for i, _ := range s {
defer fmt.Println(s[i])
}
One could use a channel to reverse a list in a function without duplicating it. It makes the code nicer in my sense.
package main
import (
"fmt"
)
func reverse(lst []string) chan string {
ret := make(chan string)
go func() {
for i, _ := range lst {
ret <- lst[len(lst)-1-i]
}
close(ret)
}()
return ret
}
func main() {
elms := []string{"a", "b", "c", "d"}
for e := range reverse(elms) {
fmt.Println(e)
}
}
In 2022, you could use generics to reverse any slice in-place:
func reverse[S ~[]E, E any](s S) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
}
When I need to extract elements from a slice and reverse range, I use something like this code:
// reverse range
// Go Playground: https://play.golang.org/p/gx6fJIfb7fo
package main
import (
"fmt"
)
type Elem struct {
Id int64
Name string
}
type Elems []Elem
func main() {
mySlice := Elems{{Id: 0, Name: "Alice"}, {Id: 1, Name: "Bob"}, {Id: 2, Name: "Carol"}}
for i, element := range mySlice {
fmt.Printf("Normal range: [%v] %+v\n", i, element)
}
//mySlice = Elems{}
//mySlice = Elems{{Id: 0, Name: "Alice"}}
if last := len(mySlice) - 1; last >= 0 {
for i, element := last, mySlice[0]; i >= 0; i-- {
element = mySlice[i]
fmt.Printf("Reverse range: [%v] %+v\n", i, element)
}
} else {
fmt.Println("mySlice empty")
}
}
Output:
Normal range: [0] {Id:0 Name:Alice}
Normal range: [1] {Id:1 Name:Bob}
Normal range: [2] {Id:2 Name:Carol}
Reverse range: [2] {Id:2 Name:Carol}
Reverse range: [1] {Id:1 Name:Bob}
Reverse range: [0] {Id:0 Name:Alice}
Playground: https://play.golang.org/p/gx6fJIfb7fo
You can use the funk.ForEachRight method from go-funk:
results := []int{}
funk.ForEachRight([]int{1, 2, 3, 4}, func(x int) {
results = append(results, x)
})
fmt.Println(results) // []int{4, 3, 2, 1}

Resources