Sorting in Go lang Interface - sorting

I am using Go. I have a dynamic data creation so I used an interface for adding my data.
hives := make([]map[string]interface{}, lenHive)
after some operation in this interface I added some data. In this interface some of the data are dynamically adding.
In this interface I have a data like below
[
{
"Career-Business Owner": 0,
"Career-Entry-level": 0,
"Dependents-School age children (5-18)": 0,
"date created": "2021-10-22T13:44:32.655Z",
"date created": "2021-11-04T05:03:53.805Z",
"hive_id": 114,
"name": "Rule test1122-Hive 38",
"users": 3
},
{
"Career-Business Owner": 0,
"Career-Entry-level": 0,
"Dependents-School age children (5-18)": 0,
"date created": "2021-10-22T13:44:32.655Z",
"hive_id": 65,
"name": "Rule hive44555-Hive 8",
"users": 0
}
]
now I need to sort this data with each field (need to use sorting in each field)
How can I sort filed from interface
here SortBy is the field (eg Career-Business Owner,Career-Entry-level,date created, hive_id,name,users)
if SortBy != "" {
if SortOrder == "desc" {
sort.Slice(hives, func(i, j int) bool {
return hives[i][gpi.SortBy] == hives[j][gpi.SortBy]
})
} else {
sort.Slice(hives, func(i, j int) bool {
return hives[i][gpi.SortBy] != hives[j][gpi.SortBy]
})
}
}
but the sorting is not working properly. What is the method for sorting interface ?
Or any alternative method exist for solving this?

The func you need to supply to sort.Slice should return true if the value at index i is less then the value at index i. So you should replace == and != with <, or with >= for reverse sorting.
Go has no implicit type casing so in your less func you will have to check the type of each field with something like a type switch and handle the comparison based on the type you find.
For example:
sort.Slice(hives, func(i, j int) bool {
aInt := hives[i][gpi.SortBy]
bInt := hives[j][gpi.SortBy]
switch a := aInt(type) {
case int:
if b, ok := bInt.(int); ok {
return a < b
}
panic("can't compare dissimilar types")
case string:
if b, ok := bInt.(string); ok {
return a < b
}
panic("can't compare dissimilar types")
default:
panic("unknown type")
}
})

Related

Function to sort list (array/slice) fields an any struct variable passed as input

I want to write a function that takes any struct variable as input and sorts the list fields in it. The list fields can be of simple type (int/string) or complex (structs) in which case they must implement some comparable interface which has getValue function returning an int and defines its order to be used for sorting.
Example -
type comparable interface {
getValue() int
}
type innerStruct struct {
x int
y string
}
func (s innerStruct) getValue() int {
return s.x
}
type outerStruct struct {
a []innerStruct
b []int
}
func sortListFields(in interface{}) {
// Implement this
}
func main() {
val := outerStruct{
a: []innerStruct{
{1, "abc"},
{3, "pqr"},
{2, "xyz"},
},
b: []int{9, 7, 8},
}
fmt.Println(sortListFields(val))
// Should print - {[{1 abc} {2 xyz} {3 pqr}] [7 8 9]}
}
I have been trying to implement it using reflection, but haven't been able to figure out how to sort the field, once I have determined its a slice/array.
func sortListFields(in interface{}) {
v := reflect.ValueOf(in)
for i := 0; i < v.NumField(); i++ {
fk := v.Field(i).Type().Kind()
if fk == reflect.Array || fk == reflect.Slice {
fmt.Printf("%v field is a list\n", v.Type().Field(i).Name)
// How to sort this field ???
}
}
}
I have following questions with respect to this.
Firstly (as clear from the post), how to implement sorting for the fields ?
Are there any other simpler (or may be not so simple) ways with/without reflection of achieving the same ?

How to return value of a key in nested map

I want to write a generic function func GetVal(map[interface{}]interface{}, key interface{}) interface{}. This will take a map and a key to search for and return either the value or nil.
The map can have any data type and can go to any level of nesting. For example,
var s1 = "S1"
var s2 = "S2"
var s3 = s1 + "==" + s2 + "==S3"
var s4 = s3 + "==S4"
var nestedMap = map[interface{}]interface{}{
"data": map[interface{}]interface{}{
"TEST_KEY": "1234353453",
"metadata": map[interface{}]interface{}{
"created_time": "2022-08-06",
},
"custom_metadata": map[interface{}][]interface{}{
"destroyed": []interface{}{
&s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
},
},
&s2: &[]*string{
&s1, &s2,
},
&s1: &[]int{
10, 20, 233,
},
123: &s3,
},
s3: []interface{}{
[]interface{}{
map[string]*string{
s4: &s4,
},
},
},
}
Expected return values
GetVal(nestedMap, "metadata") should return {"created_time": "2022-08-06"}
GetVal(nestedMap, "destroyed") should return
{ &s1,
map[string]interface{}{
"auth": []interface{}{
"val3", "val4", "val45",
},
},
}
Is there a way to do it without an external library?
This question looks similar to
Accessing Nested Map of Type map[string]interface{} in Golang but in my case the fields are not limited or always same
The question is kind of cryptic because the example is overcomplicated. If you want to get knowledge regarding the recurrent functions, you should start with something simpler like:
var nestedMap = map[string]any{
"k1": "v1",
"k2": map[string]any{
"nestedK1": "nestedV1",
"nestedK2": "nestedV2",
"nestedK3": map[string]any{
"superNestedK1" : "FOUND!!!",
},
},}
Otherwise, an explanation will be hard.
Then you can work on functions like:
func GetVal(data map[string]any, key string) (result any, found bool) {
for k, v := range data {
if k == key {
return v, true
} else {
switch v.(type) {
case map[string]any:
if result, found = GetVal(v.(map[string]any), key); found {
return
}
}
}
}
return nil, false}
Later you can think about adding support for fancy stuff like map[interface{}][]interface{}
However, if you really need such complicated structure, I am not sure if the whole design of application is ok.
Maybe you should also think about adding searching for a full path inside the map k2.nestedK3.superNestedK1. It will remove ambiguity.
// Supports getting value by path: i.e. k2.nestedK3.superNestedK1
// Thanks Lukasz Szymik for his answer, which inspired me to implement this functionality based on his code.
func GetValueByPathFromMap(data map[string]any, key string, passedKey string) (result any, found bool) {
keyAndPath := strings.SplitN(key, ".", 2)
currentKey := keyAndPath[0]
if passedKey != "" {
passedKey = passedKey + "." + currentKey
} else {
passedKey = currentKey
}
if _, isKeyExistInData := data[currentKey]; !isKeyExistInData {
logrus.Warnf("[W] key path { %s } not found", passedKey)
return
} else {
if len(keyAndPath) > 1 {
remainingPath := keyAndPath[1]
switch data[currentKey].(type) {
case map[string]any:
if result, found = GetValueByPathFromMap(data[currentKey].(map[string]any), remainingPath, passedKey); found {
return
}
}
} else {
return data[currentKey], true
}
}
return nil, false
}

Not getting expected results with waitgroup [duplicate]

Let's suppose I have these types:
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
and that I want to iterate on my node's attributes to change them.
I would have loved to be able to do:
for _, attr := range n.Attr {
if attr.Key == "href" {
attr.Val = "something"
}
}
but as attr isn't a pointer, this wouldn't work and I have to do:
for i, attr := range n.Attr {
if attr.Key == "href" {
n.Attr[i].Val = "something"
}
}
Is there a simpler or faster way? Is it possible to directly get pointers from range?
Obviously I don't want to change the structures just for the iteration and more verbose solutions are no solutions.
No, the abbreviation you want is not possible.
The reason for this is that range copies the values from the slice you're iterating over.
The specification about range says:
Range expression 1st value 2nd value (if 2nd variable is present)
array or slice a [n]E, *[n]E, or []E index i int a[i] E
So, range uses a[i] as its second value for arrays/slices, which effectively means that the
value is copied, making the original value untouchable.
This behavior is demonstrated by the following code:
x := make([]int, 3)
x[0], x[1], x[2] = 1, 2, 3
for i, val := range x {
println(&x[i], "vs.", &val)
}
The code prints you completely different memory locations for the value from range and the actual
value in the slice:
0xf84000f010 vs. 0x7f095ed0bf68
0xf84000f014 vs. 0x7f095ed0bf68
0xf84000f018 vs. 0x7f095ed0bf68
So the only thing you can do is to either use pointers or the index, as already proposed by jnml and peterSO.
You seem to be asking for something equivalent to this:
package main
import "fmt"
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
func main() {
n := Node{
[]Attribute{
{"key", "value"},
{"href", "http://www.google.com"},
},
}
fmt.Println(n)
for i := 0; i < len(n.Attr); i++ {
attr := &n.Attr[i]
if attr.Key == "href" {
attr.Val = "something"
}
}
fmt.Println(n)
}
Output:
{[{key value} {href http://www.google.com}]}
{[{key value} {href something}]}
This avoids creating a--possibly large--copy of type Attribute values, at the expense of slice bounds checks. In your example, type Attribute is relatively small, two string slice references: 2 * 3 * 8 = 48 bytes on a 64-bit architecture machine.
You could also simply write:
for i := 0; i < len(n.Attr); i++ {
if n.Attr[i].Key == "href" {
n.Attr[i].Val = "something"
}
}
But, the way to get an equivalent result with a range clause, which creates a copy but minimizes slice bounds checks, is:
for i, attr := range n.Attr {
if attr.Key == "href" {
n.Attr[i].Val = "something"
}
}
I'd adapt your last suggestion and use the index-only version of range.
for i := range n.Attr {
if n.Attr[i].Key == "href" {
n.Attr[i].Val = "something"
}
}
It seems simpler to me to refer to n.Attr[i] explicitly in both the line that tests Key and the line that sets Val, rather than using attr for one and n.Attr[i] for the other.
For example:
package main
import "fmt"
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []*Attribute
}
func main() {
n := Node{[]*Attribute{
&Attribute{"foo", ""},
&Attribute{"href", ""},
&Attribute{"bar", ""},
}}
for _, attr := range n.Attr {
if attr.Key == "href" {
attr.Val = "something"
}
}
for _, v := range n.Attr {
fmt.Printf("%#v\n", *v)
}
}
Playground
Output
main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}
Alternative approach:
package main
import "fmt"
type Attribute struct {
Key, Val string
}
type Node struct {
Attr []Attribute
}
func main() {
n := Node{[]Attribute{
{"foo", ""},
{"href", ""},
{"bar", ""},
}}
for i := range n.Attr {
attr := &n.Attr[i]
if attr.Key == "href" {
attr.Val = "something"
}
}
for _, v := range n.Attr {
fmt.Printf("%#v\n", v)
}
}
Playground
Output:
main.Attribute{Key:"foo", Val:""}
main.Attribute{Key:"href", Val:"something"}
main.Attribute{Key:"bar", Val:""}

Function that returns the min value of a slice based on struct's field?

I've got a Go struct such as:
type patient struct{
patientID int
age int
bodyTemp int
numberVaccines int
recordID int
}
How can I write a function that returns the min value in a slice of patient by selecting the field I'm interested in?
I'd call it like:
someSlice := []patient{patient{...},...,...}
fmt.Printf("Patient lowest temp: %v", someSlice.GetMin(bodyTemp)
Thanks!
As it has been already written in the comments, you can do it using reflection, but there is no need to do that due to performance decrease.
Option 1
As for a quick solution, I suggest you to implement a patients slice wrapper that is responsible to keep and find the data you need by criteria specified (for each field its own method). This is also not about a performance, because in your case you need to search a minimum value that has O(N) complexity (you need to iterate all the items in the slice).
package main
import (
"errors"
"fmt"
)
var (
ErrPatientsContainerIsEmpty = errors.New("patients container is empty")
)
type Patient struct{
patientID int
age int
bodyTemp int
numberVaccines int
recordID int
}
type PatientsContainer struct {
patients []Patient
}
func NewPatientsContainer() *PatientsContainer {
patients := make([]Patient, 0)
return & PatientsContainer{
patients: patients,
}
}
func (pc *PatientsContainer) Add(p Patient) {
pc.patients = append(pc.patients, p)
}
func (pc *PatientsContainer) WithMinTemp() (*Patient, error) {
if len(pc.patients) == 0 {
return nil, ErrPatientsContainerIsEmpty
}
patientWithMinTemp := &pc.patients[0]
// O(N) complexity!
for i, p := range pc.patients {
if p.bodyTemp < patientWithMinTemp.bodyTemp {
patientWithMinTemp = &pc.patients[i]
}
}
return patientWithMinTemp, nil
}
func main() {
// some patients data for testing
patients := []Patient{
{
recordID: 1,
bodyTemp: 37,
},
{
recordID: 2,
bodyTemp: 36,
},
{
recordID: 3,
bodyTemp: 38,
},
}
pc := NewPatientsContainer()
// Add to container
for _, p := range patients {
pc.Add(p)
}
patientWithMinTemp, err := pc.WithMinTemp()
if err != nil {
// handle an error
panic(err)
}
fmt.Println(patientWithMinTemp.recordID)
}
Option 2
If we are talking about an application with a big dataset (not 50 patients), the correct way is to introduce to the application a storage that supports indexes.
Use the sort.Slice function documented here: https://pkg.go.dev/sort
patients := []patient{patient{...},...,...}
sort.Slice(patients, func(i, j int) bool {
return patients[i].bodyTemp < patients[j].bodyTemp
})
minBodyTempPatient := patients[0]

Contains method for a slice

Is there anything similar to a slice.contains(object) method in Go without having to do a search through each element in a slice?
Mostafa has already pointed out that such a method is trivial to write, and mkb gave you a hint to use the binary search from the sort package. But if you are going to do a lot of such contains checks, you might also consider using a map instead.
It's trivial to check if a specific map key exists by using the value, ok := yourmap[key] idiom. Since you aren't interested in the value, you might also create a map[string]struct{} for example. Using an empty struct{} here has the advantage that it doesn't require any additional space and Go's internal map type is optimized for that kind of values. Therefore, map[string] struct{} is a popular choice for sets in the Go world.
No, such method does not exist, but is trivial to write:
func contains(s []int, e int) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
You can use a map if that lookup is an important part of your code, but maps have cost too.
Starting with Go 1.18, you can use the slices package – specifically the generic Contains function:
https://pkg.go.dev/golang.org/x/exp/slices#Contains.
go get golang.org/x/exp/slices
import "golang.org/x/exp/slices"
things := []string{"foo", "bar", "baz"}
slices.Contains(things, "foo") // true
Note that since this is outside the stdlib as an experimental package, it is not bound to the Go 1 Compatibility Promise™ and may change before being formally added to the stdlib.
With Go 1.18+ we could use generics.
func Contains[T comparable](s []T, e T) bool {
for _, v := range s {
if v == e {
return true
}
}
return false
}
The sort package provides the building blocks if your slice is sorted or you are willing to sort it.
input := []string{"bird", "apple", "ocean", "fork", "anchor"}
sort.Strings(input)
fmt.Println(contains(input, "apple")) // true
fmt.Println(contains(input, "grow")) // false
...
func contains(s []string, searchterm string) bool {
i := sort.SearchStrings(s, searchterm)
return i < len(s) && s[i] == searchterm
}
SearchString promises to return the index to insert x if x is not present (it could be len(a)), so a check of that reveals whether the string is contained the sorted slice.
Instead of using a slice, map may be a better solution.
simple example:
package main
import "fmt"
func contains(slice []string, item string) bool {
set := make(map[string]struct{}, len(slice))
for _, s := range slice {
set[s] = struct{}{}
}
_, ok := set[item]
return ok
}
func main() {
s := []string{"a", "b"}
s1 := "a"
fmt.Println(contains(s, s1))
}
http://play.golang.org/p/CEG6cu4JTf
If the slice is sorted, there is a binary search implemented in the sort package.
func Contain(target interface{}, list interface{}) (bool, int) {
if reflect.TypeOf(list).Kind() == reflect.Slice || reflect.TypeOf(list).Kind() == reflect.Array {
listvalue := reflect.ValueOf(list)
for i := 0; i < listvalue.Len(); i++ {
if target == listvalue.Index(i).Interface() {
return true, i
}
}
}
if reflect.TypeOf(target).Kind() == reflect.String && reflect.TypeOf(list).Kind() == reflect.String {
return strings.Contains(list.(string), target.(string)), strings.Index(list.(string), target.(string))
}
return false, -1
}
I think map[x]bool is more useful than map[x]struct{}.
Indexing the map for an item that isn't present will return false. so instead of _, ok := m[X], you can just say m[X].
This makes it easy to nest inclusion tests in expressions.
You can use the reflect package to iterate over an interface whose concrete type is a slice:
func HasElem(s interface{}, elem interface{}) bool {
arrV := reflect.ValueOf(s)
if arrV.Kind() == reflect.Slice {
for i := 0; i < arrV.Len(); i++ {
// XXX - panics if slice element points to an unexported struct field
// see https://golang.org/pkg/reflect/#Value.Interface
if arrV.Index(i).Interface() == elem {
return true
}
}
}
return false
}
https://play.golang.org/p/jL5UD7yCNq
Not sure generics are needed here. You just need a contract for your desired behavior. Doing the following is no more than what you would have to do in other languages if you wanted your own objects to behave themselves in collections, by overriding Equals() and GetHashCode() for instance.
type Identifiable interface{
GetIdentity() string
}
func IsIdentical(this Identifiable, that Identifiable) bool{
return (&this == &that) || (this.GetIdentity() == that.GetIdentity())
}
func contains(s []Identifiable, e Identifiable) bool {
for _, a := range s {
if IsIdentical(a,e) {
return true
}
}
return false
}
If it is not feasable to use a map for finding items based on a key, you can consider the goderive tool. Goderive generates a type specific implementation of a contains method, making your code both readable and efficient.
Example;
type Foo struct {
Field1 string
Field2 int
}
func Test(m Foo) bool {
var allItems []Foo
return deriveContainsFoo(allItems, m)
}
To generate the deriveContainsFoo method:
Install goderive with go get -u github.com/awalterschulze/goderive
Run goderive ./... in your workspace folder
This method will be generated for deriveContains:
func deriveContainsFoo(list []Foo, item Foo) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
Goderive has support for quite some other useful helper methods to apply a functional programming style in go.
The go style:
func Contains(n int, match func(i int) bool) bool {
for i := 0; i < n; i++ {
if match(i) {
return true
}
}
return false
}
s := []string{"a", "b", "c", "o"}
// test if s contains "o"
ok := Contains(len(s), func(i int) bool {
return s[i] == "o"
})
If you have a byte slice, you can use bytes package:
package main
import "bytes"
func contains(b []byte, sub byte) bool {
return bytes.Contains(b, []byte{sub})
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
Or suffixarray package:
package main
import "index/suffixarray"
func contains(b []byte, sub byte) bool {
return suffixarray.New(b).Lookup([]byte{sub}, 1) != nil
}
func main() {
b := contains([]byte{10, 11, 12, 13, 14}, 13)
println(b)
}
If you have an int slice, you can use intsets package:
package main
import "golang.org/x/tools/container/intsets"
func main() {
var s intsets.Sparse
for n := 10; n < 20; n++ {
s.Insert(n)
}
b := s.Has(16)
println(b)
}
https://golang.org/pkg/bytes
https://golang.org/pkg/index/suffixarray
https://pkg.go.dev/golang.org/x/tools/container/intsets
I created the following Contains function using reflect package.
This function can be used for various types like int32 or struct etc.
// Contains returns true if an element is present in a slice
func Contains(list interface{}, elem interface{}) bool {
listV := reflect.ValueOf(list)
if listV.Kind() == reflect.Slice {
for i := 0; i < listV.Len(); i++ {
item := listV.Index(i).Interface()
target := reflect.ValueOf(elem).Convert(reflect.TypeOf(item)).Interface()
if ok := reflect.DeepEqual(item, target); ok {
return true
}
}
}
return false
}
Usage of contains function is below
// slice of int32
containsInt32 := Contains([]int32{1, 2, 3, 4, 5}, 3)
fmt.Println("contains int32:", containsInt32)
// slice of float64
containsFloat64 := Contains([]float64{1.1, 2.2, 3.3, 4.4, 5.5}, 4.4)
fmt.Println("contains float64:", containsFloat64)
// slice of struct
type item struct {
ID string
Name string
}
list := []item{
item{
ID: "1",
Name: "test1",
},
item{
ID: "2",
Name: "test2",
},
item{
ID: "3",
Name: "test3",
},
}
target := item{
ID: "2",
Name: "test2",
}
containsStruct := Contains(list, target)
fmt.Println("contains struct:", containsStruct)
// Output:
// contains int32: true
// contains float64: true
// contains struct: true
Please see here for more details:
https://github.com/glassonion1/xgo/blob/main/contains.go
There are several packages that can help, but this one seems promising:
https://github.com/wesovilabs/koazee
var numbers = []int{1, 5, 4, 3, 2, 7, 1, 8, 2, 3}
contains, _ := stream.Contains(7)
fmt.Printf("stream.Contains(7): %v\n", contains)
It might be considered a bit 'hacky' but depending the size and contents of the slice, you can join the slice together and do a string search.
For example you have a slice containing single word values (e.g. "yes", "no", "maybe"). These results are appended to a slice. If you want to check if this slice contains any "maybe" results, you may use
exSlice := ["yes", "no", "yes", "maybe"]
if strings.Contains(strings.Join(exSlice, ","), "maybe") {
fmt.Println("We have a maybe!")
}
How suitable this is really depends on the size of the slice and length of its members. There may be performance or suitability issues for large slices or long values, but for smaller slices of finite size and simple values it is a valid one-liner to achieve the desired result.

Resources