Reading from a slice of unknown length in Golang - go

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

Related

Optimal refactor of divisibles from map

I have a function that takes input of packs which is a map of the pack size and the quantity and it takes a total quantity for an order.
I need to get all the divisibles for the pack sizes, remove all the under 1 values, and then pick the best divisible which is the lowest number remaining. This number is the key from the supplied packsizes
Note: I have a function further up the trace which eliminates any possibility of there not being a divisible.
Code:
func optimalDivisble(packs map[int]int, oq int) (int, error) {
divisables := make(map[int]float64)
for key := range packs {
divisables[key] = float64(oq) / float64(key)
}
// Remove zero divisibles
filteredDivisibles := make(map[int]float64)
for key, divisable := range divisables {
if divisable >= 1 {
filteredDivisibles[key] = divisable
}
}
// Get divisables
var divisableSlice []float64
for _, filteredDivisible := range filteredDivisibles {
divisableSlice = append(divisableSlice, filteredDivisible)
}
sort.Float64s(divisableSlice)
for key, filteredDivisible := range filteredDivisibles {
if filteredDivisible == divisableSlice[0] {
return key, nil
}
}
return 0, errors.New("Could not find a divisable for quantity")
}
Could someone help refactor this, as seeing 3 for loops doesn't seem ideal. What would be more idiomatic to Go?
You can process the packs, compute the min divisible and get the key for it in a single loop. You don't need the intermediate steps:
var minDiv float64
var minKey int
minSet:=false
for key := range packs {
divisable:=float64(oq) / float64(key)
if divisable>=1 {
if minDiv>divisable || !minSet {
minDiv=divisable
minKey=key
minSet=true
}
}
}
// minKey is what you need

Deleting multiple values from a map in Go at the same time within a loop

I'm trying to delete multiple values from my map[string][]interface{}
I am using the strings.Split function to separate each value i wish to delete, and then looping through them.
I have managed to get it so i can delete index values 0 and 1, however, 1,2 would delete index value 1, but error on index 2.
I have also managed to get it to delete a single value
My thought process was that if I can get it to delete just one value (any index i enter, inc first and last index), then i could use a loop to loop through, and delete the rest.
Everything is stored in the below:
package db
var DataStore map[string][]interface{}
The function
func HandleDelete(w http.ResponseWriter, k, v string) {
It takes the value you wish to delete in as a parameter (and the key, but that's fully functional)
The block of code the issue resides in
The loop starts at the end of the map slice, so when you remove index value 5 for example, 4 is still 4. Whereas if I go the other way, if i delete 5, 6 then becomes index 5. So 5,6 being deleted would effectively mean 5,7 is being deleted.
for i := len(db.DataStore) - 1; i >= 0; i-- {
for _, idxvalue := range values {
val, err := strconv.Atoi(idxvalue)
if err != nil {
log.Fatal(err)
return
}
dbval := db.DataStore[k][val]
if i == val {
if len(db.DataStore[k])-1 == i { //the length goes 1,2,3,4... the index goes 0,1,2,3 - therefore length -1, would be 3 - deletes the last index value
db.DataStore[k] = db.DataStore[k][:i]
} else { //delete everything else
db.DataStore[k] = append(db.DataStore[k][:i], db.DataStore[k][i+1:]...)
}
//when you delete the last value in that key, delete the key.
/*if len(db.DataStore[k]) == 0 {
delete(db.DataStore, k)
}*/
fmt.Fprintf(w, "Key: %v, Value: %v was deleted successfully", k, dbval)
}
}
}
I have tried both loops as below:
for i := len(db.DataStore) - 1; i >= 0; i-- {
Of course the reason the below didn't work, is because you're getting the length, before the loop (in the func body) which won't change after each iteration.
idx := len(db.DataStore) - 1
for i := idx; i >= 0; i-- {
The below code is to delete the index entered (this works with a single value)
if len(db.DataStore[k])-1 == i { //the length goes 1,2,3,4... the index goes 0,1,2,3 - therefore length -1, would be 3 - deletes the last index value
db.DataStore[k] = db.DataStore[k][:i]
} else { //delete everything else
db.DataStore[k] = append(db.DataStore[k][:i], db.DataStore[k][i+1:]...)
}
I expect the out put of '2,1' to delete index 1 and 2, but the actual input is that it just deletes index 1.
For example,
package main
import "fmt"
// Delete m k v elements indexed by d.
func deleteMKVD(m map[string][]interface{}, k string, d []int) {
v, ok := m[k]
if !ok {
return
}
for _, i := range d {
if 0 <= i && i < len(v) {
v[i] = nil
}
}
lw := 0
for i := range v {
if v[i] != nil {
lw++
}
}
if lw == 0 {
delete(m, k)
return
}
w := make([]interface{}, 0, lw)
for i := range v {
if v[i] != nil {
w = append(w, v[i])
}
}
m[k] = w
}
func main() {
m := map[string][]interface{}{
"k0": {"v0", "v1", "v2", "v3"},
}
fmt.Println(m)
deleteMKVD(m, "k0", []int{0, 3})
fmt.Println(m)
deleteMKVD(m, "k0", []int{1, 0})
fmt.Println(m)
}
Playground: https://play.golang.org/p/biEAxthTaj8
Output:
map[k0:[v0 v1 v2 v3]]
map[k0:[v1 v2]]
map[]
I think your problem is actually to remove elements from an array with an array of indices.
The easy fix here would be:
1) Find all the indices with certain k, make it an array(vals []int).
2) Sort this array int descendent. and iterate this array to delete
3) Then iterate this array to delete the elements.
In this way, every time you delete an element, it won't touch other elements' indices.
It may not be most efficient, but it would be a quick fix.
BTW, I think for i := len(db.DataStore) - 1; i >= 0; i--is not what you want.
If I understand correctly, this code here seems to make sure the val is the largest index in those indices.
So instead of write i:=len(db.DataStore) - 1, you actually need i:=len(db.DataStore[k])-1

Find the minimum value in golang?

In the language there is a minimum function https://golang.org/pkg/math/#Min But what if I have more than 2 numbers? I must to write a manual comparison in a for loop, or is there another way? The numbers are in the slice.
No, there isn't any better way than looping. Not only is it cleaner than any other approach, it's also the fastest.
values := []int{4, 20, 0, -11, -10}
min := values[0]
for _, v := range values {
if (v < min) {
min = v
}
}
fmt.Println(min)
EDIT
Since there has been some discussion in the comments about error handling and how to handle empty slices, here is a basic function that determines the minimum value. Remember to import errors.
func Min(values []int) (min int, e error) {
if len(values) == 0 {
return 0, errors.New("Cannot detect a minimum value in an empty slice")
}
min = values[0]
for _, v := range values {
if (v < min) {
min = v
}
}
return min, nil
}
General answer is: "Yes, you must use a loop, if you do not know exact number of items to compare".
In this package Min functions are implemented like:
// For 2 values
func Min(value_0, value_1 int) int {
if value_0 < value_1 {
return value_0
}
return value_1
}
// For 1+ values
func Mins(value int, values ...int) int {
for _, v := range values {
if v < value {
value = v
}
}
return value
}
You should write a loop. It does not make sense to create dozens of function in standard library to find min/max/count/count_if/all_of/any_of/none_of etc. like in C++ (most of them in 4 flavours according arguments).

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