Go: Check if every item in a slice meets a condition [closed] - go

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 7 days ago.
Improve this question
What would be the most elegant way to check if every item in a slice meets some condition? In my specific scenario, I have a slice of bytes: [16]byte. I need to check if all bytes are 0.
In JS, for example, I would do something like that:
const uint8Array = new Uint8Array([0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0])//Can be thought of as an array of "bytes"
const isEmpty = uint8Array.every(byte=>byte === 0)//Check that every "byte" is zero
console.log(isEmpty)//false
What's the cleanest and most straightforward way to do this in Go?

For readability and flexibility (e.g. if you need to operate on types other than byte), you may benefit from writing a small All generic function that
accepts a slice and a predicate on the element type of that slice, and
returns true if and only if the predicate is satisfied for all elements of the slice.
You'll then be free to put that generic function to use with different slices and predicates.
package main
import "fmt"
func main() {
bs := []byte{15: 1} // slice of 16 bytes, all but the last one of which are zero
isZero := func(b byte) bool { return b == 0 }
fmt.Println(All(bs, isZero)) // false
}
func All[T any](ts []T, pred func(T) bool) bool {
for _, t := range ts {
if !pred(t) {
return false
}
}
return true
}
(Playground)
No need to create a library for that All function, though; a little copying is better than a little dependency.

It would be easy if you use the bytes package, here is an example :
func main() {
n := []byte{0,0,0,0,0,0,0}
b := bytes.ContainsRune(n, 1)
fmt.Println(b)
}
In bytes package there are multiple methods you can call for your result, like checking char, or multiple contains etc.

The most straightforward way is to use a range-based for loop, since as far as I'm aware, Go doesn't have built-in function similar to .ForEach.
If you don't need an index, you can omit it from the loop and you will have something similar:
isEmpty := true
for _, val := range uint8Array {
if val != 0 {
isEmpty=false
break
}
}
fmt.Println(isEmpty)
If you use the function repeatedly, you can define it as your own separate function as well.
func IsEmpty(arr *[]any) bool {
for _, val := range *arr {
if val != 0 {
return false
}
}
return true
}
Although the last one might cause issues for some data types.

Related

Why is the slice field of a struct not appended to? [duplicate]

This question already has answers here:
Assign a new value to a struct field
(2 answers)
Closed 10 months ago.
The output of the following code surprises me:
package main
import (
"fmt"
)
type Thing struct {
mappings map[string]int
orderings []string
}
func NewThing() Thing {
t := Thing{}
t.mappings = make(map[string]int)
return t
}
func (t Thing) Add(s string) {
t.mappings[s] = 1
t.orderings = append(t.orderings, s)
}
func main() {
t := NewThing()
t.Add("foo")
if len(t.mappings) == len(t.orderings) {
fmt.Printf("Equal lengths: %v versus %v", t.mappings, t.orderings)
} else {
fmt.Printf("Unequal lengths: %v versus %v", t.mappings, t.orderings)
}
}
When run on the playground (https://play.golang.org/p/Ph67tHOt2Z_I) the output is this:
Unequal lengths: map[foo:1] versus []
I believe I'm treating the slice correctly; from my understanding it is initialized to nil in NewThing(), and is appended to in Add() (ensuring that the value returned from append is only assigned to its first argument).
Am I missing something incredibly obvious?
I looked at the following resources for an explanation:
https://gobyexample.com/slices - only uses either slice literals (i.e. not a struct field) or slices with set capacities, and I will not know the final size of t.orderings. It's my understanding that append should perform the extension and allocation automatically.
https://go.dev/blog/slices-intro - again, all demonstrations use slice literals. If the fields are moved out of the struct things work as expected. It's only once in the struct that this behavior occurs.
https://yourbasic.org/golang/gotcha-append/ - while it does describe behavior where append does not work as expected, the explanation involves append reusing memory when the slice has enough capacity for a new element, causing unexpected behavior when attempts to append the same array to two different copies. In my case, there is no reassignment of slice operations such as the one in this article, which is discouraged (some_var = append(some_other_var, elem)).
And I looked at the following questions for inspiration:
Go - append to slice in struct: the solution to this question was to assign the result of append back to the field, which I have done.
Correct way to initialize empty slice: the explanation is that slices don't have to be initialized, and can be left as nil and "appended to with allocation", so I believe I'm fine not initializing Thing.orderings.
Incase you don't want to use a pointer ,you can declare a global variable for Thing struct and assign it with the value of t from add function.Here is the code for the same logic :
package main
import (
"fmt"
)
var thing Thing
type Thing struct {
mappings map[string]int
orderings []string
}
func NewThing() Thing {
t := Thing{}
t.mappings = make(map[string]int)
return t
}
func (t Thing) Add(s string) {
t.mappings[s] = 1
t.orderings = append(t.orderings, s)
thing = t
}
func main() {
t := NewThing()
t.Add("foo")
if len(thing.mappings) == len(thing.orderings) {
fmt.Printf("Equal lengths: %v versus %v", thing.mappings, thing.orderings)
} else {
fmt.Printf("Unequal lengths: %v versus %v", thing.mappings, thing.orderings)
}
}
Output:
Equal lengths: map[foo:1] versus [foo]

what is the best way to convert []int64 to []uint64 [duplicate]

This question already has answers here:
How to convert a slice of one numeric type to another type
(2 answers)
Closed 3 years ago.
I want to convert a slice of []int64 to []uint64, what is the most efficient and elegant way? I just know the below way:
func convert(userIDs ...int64) []uint64 {
uIDs := make([]uint64, len(userIDs))
for index, uID := range userIDs {
uIDs[index] = uint64(uID)
}
fmt.Printf("%T, %v\n", uIDs, uIDs)
return uIDs
}
Without resorting to unsafe you cant avoid a loop:
b := make([]uint64, len(a))
for i, v := range a {
b[i] = uint64(v)
}
For further info/examples see this question or this one. If you really want to use unsafe then b := *(*[]uint64)(unsafe.Pointer(&a)) will work (but I would not recommend using this unless you have a compelling reason to do so).
There's only one way to convert one slice to another, as Birits have answered.
Unless you're looking for cast methods:
1) unsafe.Pointer cast *(*[]uint64)(unsafe.Pointer(&int64_slice))
2) reimport with edited singature using linkname pragma:
//go:linkname convert convert.Slice
func convert(userIDs []int64) []int64 {
return userIDs
}
//go:linkname ConvertSliceInt64ToUInt64 convert.Slice
func ConvertSliceInt64ToUInt64(userIDs ...int64) []uint64
https://play.golang.org/p/8b-yVL_Ps-c

Idiomatic and DRY solution to merging arrays of arbitrary types

I want to create a utility-function that is able to merge two given slices, determining equality by a given function.
type IsEqualTest func(interface{}, interface{}) bool
func ArrayMerge(one *[]interface{}, another *[]interface{}, comp IsEqualTest) *[]interface{} {
merged := *one
for _, element := range *another {
if !ArrayContains(one, &element, comp) {
merged = append(merged, element)
}
}
return &merged
}
func ArrayContains(container *[]interface{}, eventualContent *interface{}, comp IsEqualTest) bool {
for _, element := range *container {
if comp(element, eventualContent) {
return true
}
}
return false
}
// please don't mind the algorithmic flaws
However, as go does treat the []interface{} type as non-compatible to slices of anything (and it lacks generics), I would need to iterate over both operands, converting the type of the contained elements when calling, which is not what anyone could want.
What is the Go style of dealing with collections containing any type?
First: without generics, there is no idiomatic way of doing this.
Second: your thinking might be too influenced by other languages. You already got a function to compare, why not take it a bit further?
What I suggest below is not efficient, and it should not be done. However, if you really want to do it:
It looks like this is not a set union, but add the elements of the second slice to the first if they don't already exist in the first slice. To do that, you can pass two functions:
func merge(len1,len2 int, eq func(int,int)bool, write func(int)) {
for i2:=0;i2<len2;i2++ {
found:=false
for i1:=0;i1<len1;i1++ {
if eq(i1,i2) {
found=true
break
}
}
if !found {
write(i2)
}
}
Above, eq(i,j) returns true if slice1[i]==slice2[j], and write(j) does append(result,slice2[j]).

Convert map values to plain strings without brackets? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have a map string that looks like this
map[first:[hello] second:[world]]
The problem is that when I iterate over it and return the values they return [hello] [world] and I want them to just return hello world
// currentMap is of type map[interface{}]interface{} originally
newStringMap := make(map[string]interface{})
for k, v := range currentMap {
newStringMap[k.(string)] = v
}
return newStringMap
How can this be done?
From the below information provided by you:
when I iterate over it and return the values they return [hello] [world]
It seems that your currentMap actually stores string slices []string as values, behind the interface{} type. Assuming that above line means that you see this when printing the map using fmt.Println(), or similar functions.
map[first:[hello] second:[world]]
Here's a possible reproduction & solution of your problem::
package main
import (
"fmt"
)
func main() {
currentMap := make(map[interface{}]interface{})
currentMap["first"] = []string{"hello"}
currentMap["second"] = []string{"world"}
newStringMap := make(map[string]interface{})
fmt.Println("Problem:")
fmt.Printf("%v\n", currentMap)
fmt.Println("\nSolution:")
for k, v := range currentMap {
lst, ok := v.([]string)
//fmt.Println(lst, ok)
if ok && len(lst) > 0 {
newStringMap[k.(string)] = v.([]string)[0]
} else {
newStringMap[k.(string)] = nil
}
}
fmt.Printf("%v\n", newStringMap)
}
Which outputs to:
Problem:
map[first:[hello] second:[world]]
Solution:
map[first:hello second:world]
Try it here
https://play.golang.org/p/5XAA3m6MDX_b
It's not necessary that the content stored in currentMap is always of similar type. (if it is, then why would interface{} ever be used). Which means, don't forget your error-checking. I have tried to cover the same. You may need to add some more, based on the possible actual types in the map, similar to this section:
if ok && len(lst) > 0 {
newStringMap[k.(string)] = v.([]string)[0]
} else {
newStringMap[k.(string)] = nil
}

Is there a way to write generic code to find out whether a slice contains specific element in Go?

I want to know is there a generic way to write code to judge whether a slice contains an element, I find it will frequently useful since there is a lot of logic to fist judge whether specific elem is already in a slice and then decide what to do next. But there seemed not a built-in method for that(For God's sake, why?)
I try to use interface{} to do that like:
func sliceContains(slice []interface{}, elem interface{}) bool {
for _, item := range slice {
if item == elem {
return true
}
}
return false
}
I thought interface{} is sort of like Object of Java, but apparently, I was wrong. Should I write this every time meet with a new struct of slice? Isn't there a generic way to do this?
You can do it with reflect, but it will be MUCH SLOWER than a non-generic equivalent function:
func Contains(slice, elem interface{}) bool {
sv := reflect.ValueOf(slice)
// Check that slice is actually a slice/array.
// you might want to return an error here
if sv.Kind() != reflect.Slice && sv.Kind() != reflect.Array {
return false
}
// iterate the slice
for i := 0; i < sv.Len(); i++ {
// compare elem to the current slice element
if elem == sv.Index(i).Interface() {
return true
}
}
// nothing found
return false
}
func main(){
si := []int {3, 4, 5, 10, 11}
ss := []string {"hello", "world", "foo", "bar"}
fmt.Println(Contains(si, 3))
fmt.Println(Contains(si, 100))
fmt.Println(Contains(ss, "hello"))
fmt.Println(Contains(ss, "baz"))
}
How much slower? about x50-x60 slower:
Benchmarking against a non generic function of the form:
func ContainsNonGeneic(slice []int, elem int) bool {
for _, i := range slice {
if i == elem {
return true
}
}
return false
}
I'm getting:
Generic: N=100000, running time: 73.023214ms 730.23214 ns/op
Non Generic: N=100000, running time: 1.315262ms 13.15262 ns/op
You can make it using the reflect package like that:
func In(s, e interface{}) bool {
slice, elem := reflect.ValueOf(s), reflect.ValueOf(e)
for i := 0; i < slice.Len(); i++ {
if reflect.DeepEqual(slice.Index(i).Interface(), elem.Interface()) {
return true
}
}
return false
}
Playground examples: http://play.golang.org/p/TQrmwIk6B4
Alternatively, you can:
define an interface and make your slices implement it
use maps instead of slices
just write a simple for loop
What way to choose depends on the problem you are solving.
I'm not sure what your specific context is, but you'll probably want to use a map to check if something already exists.
package main
import "fmt"
type PublicClassObjectBuilderFactoryStructure struct {
Tee string
Hee string
}
func main() {
// Empty structs occupy zero bytes.
mymap := map[interface{}]struct{}{}
one := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "hey"}
two := PublicClassObjectBuilderFactoryStructure{Tee: "hola", Hee: "oye"}
three := PublicClassObjectBuilderFactoryStructure{Tee: "hi", Hee: "again"}
mymap[one] = struct{}{}
mymap[two] = struct{}{}
// The underscore is ignoring the value, which is an empty struct.
if _, exists := mymap[one]; exists {
fmt.Println("one exists")
}
if _, exists := mymap[two]; exists {
fmt.Println("two exists")
}
if _, exists := mymap[three]; exists {
fmt.Println("three exists")
}
}
Another advantage of using maps instead of a slice is that there is a built-in delete function for maps. https://play.golang.org/p/dmSyyryyS8
If you want a rather different solution, you might try the code-generator approach offered by tools such as Gen. Gen writes source code for each concrete class you want to hold in a slice, so it supports type-safe slices that let you search for the first match of an element.
(Gen also offers a few other kinds of collection and allows you to write your own.)

Resources