Arrays compare in golang - go

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.

Related

How can I sort string array by character a in golang

I am working on an algorithm question and I need to encode it with golang. In this question I need to sort a given string array by character 'a'. If I need to talk about the details of the question.
Question:
Write a function that sorts a bunch of words by the number of character “a”s within the
word (decreasing order). If some words contain the same amount of character “a”s then you
need to sort those words by their lengths
Input
["aaaasd", "a", "aab", "aaabcd", "ef", "cssssssd", "fdz", "kf", "zc", "lklklklklklklklkl", "l"]
Output:
["aaaasd", "aaabcd", "aab", "a", "lklklklklklklklkl", "cssssssd", "fdz", "ef", "kf", "zc", "l"]
My Solution:
func main() {
arr := []string{"aaaasd", "a", "aab", "aaabcd", "ef", "cssssssd", "fdz", "kf", "zc", "lklklklklklklklkl", "l"}
fmt.Println(mostFrequent(arr))
}
type FrequencyAndLength struct {
slice string
mostFrequent int
len int
}
func mostFrequent(arr []string) []FrequencyAndLength { // assuming no
testArray := []FrequencyAndLength{}
for _, a := range arr {
testArray = append(testArray, FrequencyAndLength{
slice: a,
mostFrequent: strings.Count(a, "a"),
len: len(a),
})
}
fmt.Println(testArray)
return testArray
}
I'm currently getting the number of a and the length of each element in it. I need to sort first by the number of a, then by length if there are even numbers of a, in descending order, but logically I'm stuck here.
Use sort.Slice() to sort any slice by a custom logic. This function expects a function that defines the "less" relation between 2 elements.
In your case a value is less than another if it contains more a characters, or if the count is equal, then resort to comparing their lengths. To count substrings, use strings.Count(). To get the length of a string, use the builtin len() function, but note that len() returns the UTF-8 encoded byte length, not the number of runes. For the letter, use utf8.RuneCountInString().
For example:
in := []string{"aaaasd", "a", "aab", "aaabcd", "ef", "cssssssd", "fdz", "kf", "zc", "lklklklklklklklkl", "l"}
sort.Slice(in, func(i, j int) bool {
s1, s2 := in[i], in[j]
count1, count2 := strings.Count(s1, "a"), strings.Count(s2, "a")
if count1 != count2 {
return count1 > count2
}
return utf8.RuneCountInString(s1) > utf8.RuneCountInString(s2)
})
fmt.Println(in)
This will output (try it on the Go Playground):
[aaaasd aaabcd aab a lklklklklklklklkl cssssssd fdz ef kf zc l]
Note that the order between elements that contain equal number of a's and have equal length is unspecified. If you want them in the same order as in your input slice, use sort.SliceStable() instead of sort.Slice().
Also note that our custom logic is not complex but not trivial either. The function may be called many times to compare elements, and the same element may be passed (asked) multiple times. If the input slice is big, it may be profitable to calculate the numer of a's and the rune length once for each element, store them in a map for example, and just query this precalculated data in the less() function.
This is how it could look like:
// Pre-calculate
type info struct{ count, length int }
calculated := map[string]info{}
for _, s := range in {
calculated[s] = info{
count: strings.Count(s, "a"),
length: utf8.RuneCountInString(s),
}
}
sort.Slice(in, func(i, j int) bool {
inf1, inf2 := calculated[in[i]], calculated[in[j]]
if inf1.count != inf2.count {
return inf1.count > inf2.count
}
return inf1.length > inf2.length
})
This outputs the same. Try it on the Go Playground.

Golang maps/hashmaps, optimizing for iteration speed

When migrating a production NodeJS application to Golang I've noticed that iteration of GO's native Map is actually slower than Node.
I've come up with an alternative solution that sacrifices removal/insertion speed with iteration speed instead, by exposing an array that can be iterated over and storing key=>index pairs inside a separate map.
While this solution works, and has a significant performance increase, I was wondering if there is a better solution to this that I could look into.
The setup I have is that its very rare something is removed from the hashmaps, only additions and replacements are common for which this implementation 'works', albeit feels like a workaround more than an actual solution.
The maps are always indexed by an integer, holding arbitrary data.
FastMap: 500000 Iterations - 0.153000ms
Native Map: 500000 Iterations - 4.988000ms
/*
Unordered hash map optimized for iteration speed.
Stores values in an array and holds key=>index mappings inside a separate hashmap
*/
type FastMapEntry[K comparable, T any] struct {
Key K
Value T
}
type FastMap[K comparable, T any] struct {
m map[K]int // Stores key => array index mappings
entries []FastMapEntry[K, T] // Array holding entries and their keys
len int // Total map size
}
func MakeFastMap[K comparable, T any]() *FastMap[K, T] {
return &FastMap[K, T]{
m: make(map[K]int),
entries: make([]FastMapEntry[K, T], 0),
}
}
func (m *FastMap[K, T]) Set(key K, value T) {
index, exists := m.m[key]
if exists {
// Replace if key already exists
m.entries[index] = FastMapEntry[K, T]{
Key: key,
Value: value,
}
} else {
// Store the key=>index pair in the map and add value to entries. Increase total len by one
m.m[key] = m.len
m.entries = append(m.entries, FastMapEntry[K, T]{
Key: key,
Value: value,
})
m.len++
}
}
func (m *FastMap[K, T]) Has(key K) bool {
_, exists := m.m[key]
return exists
}
func (m *FastMap[K, T]) Get(key K) (value T, found bool) {
index, exists := m.m[key]
if exists {
found = true
value = m.entries[index].Value
}
return
}
func (m *FastMap[K, T]) Remove(key K) bool {
index, exists := m.m[key]
if exists {
// Remove value from entries
m.entries = append(m.entries[:index], m.entries[index+1:]...)
// Remove key=>index mapping
delete(m.m, key)
m.len--
for i := index; i < m.len; i++ {
// Move all index mappings up, starting from current index
m.m[m.entries[i].Key] = i
}
}
return exists
}
func (m *FastMap[K, T]) Entries() []FastMapEntry[K, T] {
return m.entries
}
func (m *FastMap[K, T]) Len() int {
return m.len
}
The test code that was ran is:
// s.Variations is a native map holding ~500k records
start := time.Now()
iterations := 0
for _, variation := range s.Variations {
if variation.Id > 0 {
}
iterations++
}
log.Printf("Native Map: %d Iterations - %fms\n", iterations, float64(time.Since(start).Microseconds())/1000)
// Copy data into FastMap
fm := helpers.MakeFastMap[state.VariationId, models.ItemVariation]()
for key, variation := range s.Variations {
fm.Set(key, variation)
}
start = time.Now()
iterations = 0
for _, variation := range fm.Entries() {
if variation.Value.Id > 0 {
}
iterations++
}
log.Printf("FastMap: %d Iterations - %fms\n", iterations, float64(time.Since(start).Microseconds())/1000)
I think this kind of comparison and benchmarking is a little off-topic. Go implementation of map is quite different from your implementation, basically because it needs to cover a wider area of entries, the structs used in compile time are actually kind of heavy (not so much though, they basically store some information about the types you use in your map and so on), and the implementation approach is different! Go implementation of map is basically a hashmap (yours is not obviously, or it is, but the actual hashing implementation is delegated to the m map you hold internally).
One of the other factors makes you get this result is, if you take a look at this:
for _, variation := range fm.Entries() {
if variation.Value.Id > 0 {
}
iterations++
}
Basically, you're iterating over a slice, which is much easier and faster to iterate rather than a map, you have a view to an array, which holds elements of the same types next to each other, makes sense, right?
What you should do to make a better comparison would be something like this:
for _, y := range fastMap.m {
_ = fastMap.Entries()[y].Value + 1 // some simple calculation
}
If you're really looking for performance, a well written hash function and a fixed size array would be your best choice.

Sorting array of i by v[i]/w[i] in Go

I would like to sort an array of indices descendingly by v[i]/w[i] where v and w are two other arrays of integers. Here is what I have tried in Go:
package main
import "fmt"
import "sort"
func main() {
v := [3]int{5, 6, 3}
w := [3]int{4, 5, 2}
indices := make([]int, 3)
for i := range indices {
indices[i] = i
}
sort.Slice(indices, func(a, b int) bool {
return float32(v[a])/float32(w[a]) > float32(v[b])/float32(w[b])
})
fmt.Println(indices)
}
I expect the output to be [2,0,1] because 3/2 > 5/4 > 6/5 but the actual output is [0,2,1]. Could anyone help me find the where the problem is? Thank you.
To not mutate v and w arrays which can be expensive, we can just add another level of indirection into the Less function
sort.Slice(indices, func(a, b int) bool {
return float32(v[indices[a]])/float32(w[indices[a]]) > float32(v[indices[b]])/float32(w[indices[b]])
})
Playground
Sorting by definition moves items you're sorting around in the slice, therefore changing their respective indexes. However you are not moving the actual values you are sorting, which are in w and v, only the indices slice.
Since the indices slice contains the sorted "indices", you can use that to lookup the actual value for comparison.
sort.Slice(indices, func(i, j int) bool {
return float64(v[indices[i]])/float64(w[indices[i]]) > float64(v[indices[j]])/float64(w[indices[j]])
})
https://play.golang.org/p/6oFBM27bVR-
Or you could implement a type to sort all 3 values at once for example:
type indexSorter struct {
indices, w, v []int
}
func (a indexSorter) Len() int { return len(a.indices) }
func (a indexSorter) Swap(i, j int) {
a.indices[i], a.indices[j] = a.indices[j], a.indices[i]
a.w[i], a.w[j] = a.w[j], a.w[i]
a.v[i], a.v[j] = a.v[j], a.v[i]
}
func (a indexSorter) Less(i, j int) bool {
return float64(a.v[i])/float64(a.w[i]) > float64(a.v[i])/float64(a.w[j])
}
https://play.golang.org/p/EFUkHWgjo5U
This is happening because the sort function changes the indices while it is sorting but your accompanying arrays v and w remain constant.
The best way to do what you want is to create a single array with v and w both contained in a struct and then order that array.

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
}

How to check the uniqueness inside a for-loop?

Is there a way to check slices/maps for the presence of a value?
I would like to add a value to a slice only if it does not exist in the slice.
This works, but it seems verbose. Is there a better way to do this?
orgSlice := []int{1, 2, 3}
newSlice := []int{}
newInt := 2
newSlice = append(newSlice, newInt)
for _, v := range orgSlice {
if v != newInt {
newSlice = append(newSlice, v)
}
}
newSlice == [2 1 3]
Your approach would take linear time for each insertion. A better way would be to use a map[int]struct{}. Alternatively, you could also use a map[int]bool or something similar, but the empty struct{} has the advantage that it doesn't occupy any additional space. Therefore map[int]struct{} is a popular choice for a set of integers.
Example:
set := make(map[int]struct{})
set[1] = struct{}{}
set[2] = struct{}{}
set[1] = struct{}{}
// ...
for key := range(set) {
fmt.Println(key)
}
// each value will be printed only once, in no particular order
// you can use the ,ok idiom to check for existing keys
if _, ok := set[1]; ok {
fmt.Println("element found")
} else {
fmt.Println("element not found")
}
Most efficient is likely to be iterating over the slice and appending if you don't find it.
func AppendIfMissing(slice []int, i int) []int {
for _, ele := range slice {
if ele == i {
return slice
}
}
return append(slice, i)
}
It's simple and obvious and will be fast for small lists.
Further, it will always be faster than your current map-based solution. The map-based solution iterates over the whole slice no matter what; this solution returns immediately when it finds that the new value is already present. Both solutions compare elements as they iterate. (Each map assignment statement certainly does at least one map key comparison internally.) A map would only be useful if you could maintain it across many insertions. If you rebuild it on every insertion, then all advantage is lost.
If you truly need to efficiently handle large lists, consider maintaining the lists in sorted order. (I suspect the order doesn't matter to you because your first solution appended at the beginning of the list and your latest solution appends at the end.) If you always keep the lists sorted then you you can use the sort.Search function to do efficient binary insertions.
Another option:
package main
import "golang.org/x/tools/container/intsets"
func main() {
var (
a intsets.Sparse
b bool
)
b = a.Insert(9)
println(b) // true
b = a.Insert(9)
println(b) // false
}
https://pkg.go.dev/golang.org/x/tools/container/intsets
This option if the number of missing numbers is unknown
AppendIfMissing := func(sl []int, n ...int) []int {
cache := make(map[int]int)
for _, elem := range sl {
cache[elem] = elem
}
for _, elem := range n {
if _, ok := cache[elem]; !ok {
sl = append(sl, elem)
}
}
return sl
}
distincting a array of a struct :
func distinctObjects(objs []ObjectType) (distinctedObjs [] ObjectType){
var output []ObjectType
for i:= range objs{
if output==nil || len(output)==0{
output=append(output,objs[i])
} else {
founded:=false
for j:= range output{
if output[j].fieldname1==objs[i].fieldname1 && output[j].fieldname2==objs[i].fieldname2 &&......... {
founded=true
}
}
if !founded{
output=append(output,objs[i])
}
}
}
return output
}
where the struct here is something like :
type ObjectType struct {
fieldname1 string
fieldname2 string
.........
}
the object will distinct by checked fields here :
if output[j].fieldname1==objs[i].fieldname1 && output[j].fieldname2==objs[i].fieldname2 &&......... {

Resources