How do I remove duplicates from a struct slice? [closed] - go

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I have a struct like this:
type structData struct {
dataName string
dataNum int
}
And I have created a slice out of them, like so:
dataSlice := []*structData{}
I have a loop that populates the dataName string and just after this, I want the struct slice to be checked through and duplicates removed.
I mention this specifically because currently, dataNum is 0. So, I don't want to check if the string inside my struct is same or not, it is totally fine checking if the entire struct is equal (if that's possible, else it is also OKAY for me to check duplicates in the dataName string, I just don't know what would look better in design).
An example output of what my struct slice looks like:
&{dataname1 0}
&{dataname1 0}
&{dataname2 0}
&{dataname2 0}
What I want it to look like:
&{dataname1 0}
&{dataname2 0}

You can use a map to check for duplicates, where your struct is the key to the map.
package main
import (
"fmt"
)
type structData struct {
dataName string
dataNum int
}
func (d *structData) String() string {
return fmt.Sprintf("(%s,%d)", d.dataName, d.dataNum)
}
func main() {
dataSlice := []*structData{
{"dataname1", 0},
{"dataname1", 0},
{"dataname2", 0},
{"dataname2", 0},
}
m := map[structData]struct{}{}
dataSlice2 := []*structData{}
for _, d := range dataSlice {
if _, ok := m[*d]; !ok {
dataSlice2 = append(dataSlice2, d)
m[*d] = struct{}{}
}
}
fmt.Printf("%v\n", dataSlice)
fmt.Printf("%v\n", dataSlice2)
}
https://play.golang.org/p/wL-SfBCMGQj

Related

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

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.

Is there a way to specify the type that goes into lists in Go? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed last year.
Improve this question
Is there a way to specify the type that goes into lists in Go? I am new to Go and most of what I see from Google searches mentions slices and I even meant to ask this question. I am stuck with the code with lists and can't modify to slices.
The documentation mentions that lists use an interface for the element.
I ask because I wrote this code:
a := list.New()
a.PushBack(x)
and got this error from the code that runs my file.
panic: interface conversion: interface {} is int, not fileA.TypeA
My hunch is to create a list that only accepts fileA.TypeA but am open to suggestions if there are other ways to fix this.
I guess when you're reading data from list, you use wrong type to convert data.
For example.
package main
import (
"container/list"
"fmt"
)
type User struct {
name string
}
func main() {
l := list.New()
l.PushBack(User{name: "Jack"})
l.PushBack(2)
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value.(int))
}
}
// panic: interface conversion: interface {} is main.User, not int
The list have User & int two types, but if you only use int to convert all data in list, it'll throw panic error. You need to use correct type to convert.
Then you could detect type like following example.
package main
import (
"container/list"
"fmt"
)
type User struct {
name string
}
func do(i interface{}) {
switch v := i.(type) {
case int:
fmt.Printf("This type is int: %d", v)
case User:
fmt.Printf("This is User type: %#v\n", v)
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
l := list.New()
l.PushBack(User{name: "Jack"})
l.PushBack(2)
l.PushBack(3)
for e := l.Front(); e != nil; e = e.Next() {
do(e.Value)
}
}

update map[string]int from string value [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I am trying to parse a json-like string which looks like this.
"abc:9, bar:3"
What I would like to have at the end is a map[string]int which looks like this:
map[string]int{"abc":9, "bar":3}
I have gotten as far as splitting it into a set of 'pairs', like so:
`["abc:9", "bar:3"]
I am struggling with how to get that structure into the final map[string]int. I have tried ranging over the slice, but I am missing how to actually get it into the map.
val := "abc:9, bar:3"
lsd := make(map[string]int)
c := strings.Split(val, ",")
for k, v := range c {
lsd = v[k] // where I am struggling, I know this is wrong, but I can't seem to find the proper syntax and tools for this
}
Can anyone point me in the right direction to end up with the map[string]int I am looking for here?
This is a tiny bit cheesy but I was having trouble making fmt.Sscanf grok the pattern, so I am just splitting again. And you may have been missing strconv - strconv.Atoi is a quick converter.
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
lsd := make(map[string]int)
toParse := "abc:5, foo:5"
parts := strings.Split(toParse, ", ")
for _, p := range parts {
results := strings.SplitN(p, ":", 2)
val, err := strconv.Atoi(results[1])
if err != nil {
panic(err) //probably want to do somethig better
}
lsd[results[0]] = val
}
fmt.Printf("%#v", lsd)
}
map[string]int{"abc":5, "foo":5}
https://play.golang.org/p/UadibEzTXWU

How to get the address of a struct field through reflect in GO [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
I'm working on a code to deserialize streams of bytes into objects and I'm stuck on getting the pointer of the field of a struct.
Basically how the code works is as follows: it gets the pointer to a struct, then depending on the type it serializes it, ex. if it's an integer it takes the next 4 bytes. The tricky case is if it's a struct because I have to recursively run Deserialize on all of its attributes and I don't know how to get the address of its field to pass them to Deserialize.
func Deserialize(objPtr interface{}, b []byte) (bytesRead int) {
// it should be the address of the object
val := reflect.ValueOf(objPtr).Elem()
valPtr := reflect.ValueOf(objPtr)
// check if either the object or *object is Serializable
_, isSerializable := (val.Interface()).(Serializable)
_, bo := (valPtr.Interface()).(Serializable)
isSerializable = isSerializable || bo
// specific type serialization
if isSerializable{
return objPtr.(Serializable).Deserializebyte(b)
}
switch val.Kind() {
case reflect.Uint32, reflect.Int, reflect.Int32:
res := reflect.ValueOf(binary.LittleEndian.Uint32(b[:4]))
valPtr.Set(res)
return 4
case reflect.Uint64, reflect.Int64:
res := reflect.ValueOf(binary.LittleEndian.Uint32(b[:8]))
valPtr.Set(res)
return 8
case reflect.Struct:
n_bytes := 0
for i := 0; i < val.NumField(); i++ {
// stuck in here
valPtr.Elem()
// I don't think the next line works
last_n_bytes := Deserialize(&(valPtr.Elem().Field(i).Interface()), b)
n_bytes += last_n_bytes
b = b[last_n_bytes:]
}
//valPtr.Set(res)
return n_bytes
default:
panic("this panic is for debug, every case should be handled above")
res := val.Bytes()
valPtr.Set(res)
return len(val.Bytes())
}
return 0
}
Use the reflect API to get the address of the field:
last_n_bytes := Deserialize(valPtr.Elem().Field(i).Addr().Interface(), b)
The superint example panics because the application takes the address of an unexported field through the reflect API. That's not allowed because it would allow another package to modify the field.
Here's a working example with exported fields:
type superint struct {
A int
B int
}
func (s *superint) lol() {}
type a interface{ lol() }
func main() {
i := superint{A: 1, B: 9}
valPtr := reflect.ValueOf(&i)
fmt.Printf("%v \n", &i.A)
fmt.Printf("%v \n", valPtr.Elem().Field(0).Addr().Interface())
}

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
}

Resources