How do I check for an empty slice? - go

I am calling a function that returns an empty array if there are no values.
When I do this it doesn't work:
if r == [] {
fmt.Println("No return value")
}
The work around I'm using is:
var a [0]int
if r == a {
fmt.Println("No return value")
}
But declaring a variable just to check the return value doesn't seem right. What's the better way to do this?

len() returns the number of elements in a slice or array.
Assuming whatever() is the function you invoke, you can do something like:
r := whatever()
if len(r) > 0 {
// do what you want
}
or if you don't need the items
if len(whatever()) > 0 {
// do what you want
}

You can just use the len function.
if len(r) == 0 {
fmt.Println("No return value")
}
Although since you are using arrays, an array of type [0]int (an array of int with size 0) is different than [n]int (n array of int with size n) and are not compatible with each other.
If you have a function that returns arrays with different lengths, consider using slices, because function can only be declared with an array return type having a specific length (e.g. func f() [n]int, n is a constant) and that array will have n values in it (they'll be zeroed) even if the function never writes anything to that array.

You can use the inbuilt function provided by Golang
len()
It will helps you to easily find a slice is empty or not.
if len( yourFunction() ) == 0 {
// It implies that your array is empty.
}

Related

Reading from a slice of unknown length in Golang

I'm trying to replicate this algorithm for finding duplicates in an array in Golang. Here's the javascript version:
function hasDuplicateValue(array) {
let existingNumbers = [];
for(let i = 0; i < array.length; i++) {
if(existingNumbers[array[i]] === 1) {
return true;
} else {
existingNumbers[array[i]] = 1;
}
}
return false;
}
On line 2, the algorithm creates an empty array of unknown length, and then adds 1 to an index in the array corresponding with each number that it finds (e.g. if it finds the number 3 in the array, it will add a 1 to index 3 in existing numbers.
I'm wondering — how do I replicate this in Golang (since we need to have slots allocated in the slice before reading it). Would I first need to find the max value in the array and then declare the existingNumbers slice to be of that same size?
Or is there a more efficient way of doing this (instead of searching through the array and finding the max value before constructing the slice).
Thanks!
Edit:
I realized that I can't do this with a slice because I can't read from an empty value. However, as #icza suggested, it will work with a map:
func findDuplicates(list []int)(bool) {
temp := make(map[int]int)
for _, elem := range list {
if temp[elem] == 1 {
return true
} else {
temp[elem] = 1
}
}
return false
}
As comments, I would also suggest using a map to keep the state of the duplications, but we can use map[int]struct{} because empty structs are not consumed any memory in Go.
And also I have simplified the code a bit and it is as follows.
func findDuplicates(list []int) bool {
temp := make(map[int]struct{})
for _, elem := range list {
if _, ok := temp[elem]; ok {
return true
}
temp[elem] = struct{}{}
}
return false
}
Full code can be executed here

Sorting a slice based on the order of the elements in another slice

I am attempting to order a slice based on the order of the elements within another slice. My sort function works when I only have one of each type within my slice I want to order however when I start adding more elements the ordering breaks.
I have created an example within the Golang playground.
https://play.golang.org/p/e9sHIeV2qSf
I want to order my Variant slice by the Code field and have it the same as order as the codes appear in the Language struct.
Below is the sort function I am using:
sort.Slice(variants, func(i, j int) bool {
for k, language := range languages {
if language.Code == variants[i].Code {
return i >= k
}
}
return false
})
The current order it's returning is:
Sorted slice: [{Code:en-GB} {Code:en-US} {Code:en-GB} {Code:es-ES}
{Code:en-GB} {Code:en-GB} {Code:en-GB} {Code:en-GB} {Code:es-ES}]
When the order within my Language struct is:
"en-GB", "en-US", "fr-FR", "es-ES"
I think to do this, you need to build a ranking of your languages:
var langMap map[string]int
for i, lang := range languages {
langMap[lang.Code] = i
}
With this, it becomes trivial to just look up the ranking of each item in variants, and return the appropriate value:
sort.Slice(variants, func(i, j int) bool {
iRank, jRank := langMap[variants[i].Code], langMap[variants[j].Code]
return iRank < jRank
})
If there's a chance you may have inputs that are not in the pre-sorted list, you can sort them last:
sort.Slice(variants, func(i, j int) bool {
iRank, iExists := langMap[variants[i].Code]
jRank, jExists := langMap[variants[j].Code]
switch (
case iExists && jExists:
// Both exist in the pre-ordered list, so sort by rank
return iRank < jRank
case !iExists && !jExists:
// Neither exists in the pre-ordered list, sort alphabetically
return variants[i].Code < variants[j].Code
case iExists:
// Only i exists, so sort it before j
return true
default: // jExists
// Only j exists, so sort it after i
return false
)
})
It is logically possible to do the same by looping through your reference list each time, as you're attempting, but it's much harder to reason about, and far less efficient.

When appending value to slice, value is different from original value

consider this piece of code:
package main
import (
"fmt"
)
func main() {
fmt.Println(Part(11))
}
func Part(n int) string {
enumResult := [][]int{}
enum(n, n, []int{}, &enumResult)
fmt.Println(enumResult)
fmt.Println(40, enumResult[40])
return ""
}
var abc int = 0
func enum(n int, top int, pre []int, result *[][]int) {
var i int
if n > top {
i = top
} else {
i = n
}
for ; i > 0; i-- {
tempResult := append(pre, i)
if n-i == 0 {
/* if tempResult[0] == 3 && tempResult[1] == 3 && tempResult[2] == 3 && tempResult[3] == 2 {
tempResult = append(tempResult, 12345)
}*/
fmt.Println(abc, tempResult)
abc++
*result = append(*result, tempResult)
} else {
enum(n-i, i, tempResult, result)
}
}
}
When I run this code
I append value '[3,3,3,2]' to 'enumResult'
but If I check the value of 'enumResult' then '[3,3,3,1]' is appear
it`s index is 40 =>enumResult[40]
(other value is correct)
I don`t know why this is happening
Can you explain to me why?
The problem is indeed due to append.
There are two thing about append. First is, that append doe not necessarily copy memory. As the spec specifies:
If the capacity of s is not large enough to fit the additional values,
append allocates a new, sufficiently large underlying array that fits
both the existing slice elements and the additional values. Otherwise,
append re-uses the underlying array.
This may cause unexpected behavior if you are not clear. A playground example: https://play.golang.org/p/7A3JR-5IX8o
The second part is, that when append does copy memory, it grows the capacity of the slice. However, it does not grow it just by 1. A playground example: https://play.golang.org/p/STr9jMqORUz
How much append grows a slice is undocumented and considered an implentation details. But till Go 1.10, it follows this rule:
Go slices grow by doubling until size 1024, after which they grow by
25% each time.
Note that when enabling race-detector, this may change. The code for growing slice is located in $GOROOT/src/runtime/slice.go in growslice function.
Now back to the question. It should be clear now that your code did append from a same slice with sufficient capacity due to growth of the slice from append before. To solve it, make a new slice and copy the memory.
tempResult := make([]int,len(pre)+1)
copy(tempResult,pre)
tempResult[len(pre)] = i

Arrays compare in golang

I need to compare 2 arrays of uint32, something like this
func in(a uint32, list []uint32) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}
for n := 0 ;n < len(a); n++ {
fmt.Println(in(a[n], b))
}
// a and b []uint32
but I think it is not the most optimal way
Why not just use == if you are actually using arrays?
https://golang.org/ref/spec#Comparison_operators
Array values are comparable if values of the array element type are comparable. Two array values are equal if their corresponding elements are equal.
If you are using slices, you can use reflect.DeepEqual.
But, from your code, it seems like you should look into https://godoc.org/golang.org/x/tools/container/intsets
Then, you create your two intsets.Sparse and could then do:
func main() {
s1 := intsets.Sparse{}
s2 := intsets.Sparse{}
s1.Insert(1)
s1.Insert(2)
s1.Insert(3)
s2.Insert(1)
s2.Insert(2)
//s1:{1,2,3}
//s2:{1,2}
fmt.Println(s1.SubsetOf(&s2), s2.SubsetOf(&s1))
//false, true
}
which will ignore duplicates, but let you know if s1 is a subset of s2, meaning every element in s1 exists in s2.

Check if all items in a slice are equal

I need to create a function that:
returns true if all elements in a slice are equal (they will all be the same type)
returns false if any elements in a slice are different
The only way I can think of doing it is to reverse the slice, and compare the slice and the reversed slice.
Is there a better way to do this thats good syntax and more efficient?
I am not sure what your though process was for reversing the slice was, but that would be unnecessary. The simplest algorithm would be to check to see if all elements after the the first are equal to the first:
func allSameStrings(a []string) bool {
for i := 1; i < len(a); i++ {
if a[i] != a[0] {
return false
}
}
return true
}
Although there is an accepted answer, I'm just posting it with range keyword.
func allSameStrings(a []string) bool {
for i, v := range(a) {
if v != a[0] {
return false
}
}
return true
}

Resources