Go Unpacking Array As Arguments - go

So in Python and Ruby there is the splat operator (*) for unpacking an array as arguments. In Javascript there is the .apply() function. Is there a way of unpacking an array/slice as function arguments in Go? Any resources for this would be great as well!
Something along the lines of this:
func my_func(a, b int) (int) {
return a + b
}
func main() {
arr := []int{2,4}
sum := my_func(arr)
}

You can use a vararg syntax similar to C:
package main
import "fmt"
func my_func( args ...int) int {
sum := 0
for _,v := range args {
sum = sum + v
}
return sum;
}
func main() {
arr := []int{2,4}
sum := my_func(arr...)
fmt.Println("Sum is ", sum)
}
Now you can sum as many things as you'd like. Notice the important ... after when you call the my_func function.
Running example: http://ideone.com/8htWfx

Either your function is varargs, in which you can use a slice with the ... notation as Hunter McMillen shows, or your function has a fixed number of arguments and you can unpack them when writing your code.
If you really want to do this dynamically on a function of fixed number of arguments, you can use reflection:
package main
import "fmt"
import "reflect"
func my_func(a, b int) (int) {
return a + b
}
func main() {
arr := []int{2,4}
var args []reflect.Value
for _, x := range arr {
args = append(args, reflect.ValueOf(x))
}
fun := reflect.ValueOf(my_func)
result := fun.Call(args)
sum := result[0].Interface().(int)
fmt.Println("Sum is ", sum)
}

https://play.golang.org/p/2nN6kjHXIsd
I had a reason to unpack some vars from a map[string]string with single quotes around some of them as well as without. Here's the logic for it and the play link up top has the full working snippet.
func unpack(a map[string]string) string {
var stmt, val string
var x, y []string
for k, v := range a {
x = append(x, k)
y = append(y, "'"+v+"'")
}
stmt = "INSERT INTO tdo.rca_trans_status (" + strings.Join(x, ", ")
val = ") VALUES (" + strings.Join(y, ",") + ");"
return stmt + val}
Which presents cleanly for a mssql query as:
INSERT INTO tdo.rca_trans_status (rca_json_body, original_org, md5sum, updated, rca_key) VALUES ('blob','EG','2343453463','2009-11-10 23:00:00','prb-180');

No, there's no direct support for this in the language. Python and Ruby, as well as Javascript you're mentioning; are all dynamic/scripting languages. Go is way closer to, for example, C than to any dynamic language. The 'apply' functionality is handy for dynamic languages, but of little use for static languages like C or Go,

Related

What does the underscore(_) do in for loop Golang?

I am just getting started learning the Golang language!
In for loop, I saw sometimes adding an underscore or without underscore.
Whatever add _ or not, I got the same result.
package main
import (
"fmt"
)
func main() {
doSomething()
sum := addValues(5, 8)
fmt.Println("The sum is", sum)
multiSum, multiCount := addAllValues(4, 7, 9)
fmt.Println("multisum", multiSum)
fmt.Println("multiCount", multiCount)
}
func doSomething() {
fmt.Println("Doing Something")
}
func addValues(value1 int, value2 int) int {
return value1 + value2
}
func addAllValues(values ...int) (int, int) {
total := 0
for _, v := range values {
total += v
}
return total, len(values)
}
func addAllValues(values ...int) (int, int) {
total := 0
for v := range values {
total += v
}
return total, len(values)
}
All I know is I don't care about the index. Is that all? or there is something more what I have to know??
I really appreciate your help!
For range over slices:
In for v := range values { the v is the index of the element in the slice.
In for _, v := range values { the v is the actual element value.
In for i, v := range values { the i is the index and the v is the element.
In for i, _ := range values { the i is the index of the element in the slice.
You can run this playground example to see the differences.
Range expression 1st value 2nd value
array or slice a [n]E, *[n]E, or []E index i int a[i] E
string s string type index i int see below rune
map m map[K]V key k K m[k] V
channel c chan E, <-chan E element e E
For more details see the spec.
If you don't want to use the variable that iterates in the loop, you can use _ to simply let Go ignore it:
mySlice := [int]{1,3,4,59,5}
for _,x := range mySlice {
fmt.Println(x)
}
By placing underscore you are telling the compiler this:
Ok, I'm aware that this function is returning something but I don't care! For example:
package main
import "fmt"
func main() {
mul1, add1 := test_function(2, 3)
fmt.Println(mul1, add1)
mul2, _ := test_function(4, 5)
fmt.Println(mul2)
_, add3 := test_function(7, 8)
fmt.Println(add3)
}
func test_function(a int, b int) (mul int, add int) {
return a * b, a + b
}
just to add to the amazing answer above:
I think one of the main benefits is to maintain readability in your program: if you replace the blank identifier with a variable then you have to use it or your program will not compile.
also this decrease memory allocation be neglecting one of the returned parameters...

How to fill a slice with scan values

I'm brand new to Go and having trouble getting fmt.scan() to fill a slice. The number of input values is dynamic and I can't use a for loop. My initial thought was to try this:
package main
import "fmt"
func main() {
var x []int
fmt.Println("Enter input")
fmt.Scanf("%v", append(x))
fmt.Println(x)
}
Which obviously doesn't work. Can someone point me in the right direction?
[Get] fmt.Scan() to fill a slice. The number of input values is dynamic and I can't use a for loop.
Perhaps, something like this:
package main
import "fmt"
func input(x []int, err error) []int {
if err != nil {
return x
}
var d int
n, err := fmt.Scanf("%d", &d)
if n == 1 {
x = append(x, d)
}
return input(x, err)
}
func main() {
fmt.Println("Enter input:")
x := input([]int{}, nil)
fmt.Println("Input:", x)
}
Output:
Enter input:
1
2 3
4
5 6 7
Input: [1 2 3 4 5 6 7]
ADDENDUM:
When storage is allocated for a variable or a new value is created, and no explicit initialization is provided, the variable or value is given a default value, the zero value for its type: nil for slices. Conversions are expressions of the form T(x) where T is a type and x is an expression that can be converted to type T. []int(nil) is a conversion to the zero value for the slice value []int.
x := input([]int(nil), nil)
is equivalent to
x := input([]int{}, nil)
or
var x []int
x = input(x, nil)
I have revised my answer to use:
x := input([]int{}, nil)
I'm new to Go, so this are my 2cents as a newbie.
func main(){
var numsToInput int
fmt.Println("Welcome user!")
fmt.Println("How many numbers would you like to scale today?")
fmt.Scan(&numsToInput)
fmt.Println("Type please the ", num, " numbers: ")
var values []float32 // Empty slice
for i := 0; i < num; i++{
var val float32
fmt.Scanln(&val)
values = append(values, val)
}
fmt.Println(values)
}
It's not a very elaborate program, but certainly it's simple.
I hope it was useful.
Using simple packages and more logic, you could try this,
package main
import "fmt"
func main() {
var ele rune
var size int
var sli = make([]int,0,1)
size = cap(sli)
for i:=0; i<=size; i++{
if i>=len(sli){
size=size+1
}
ele = 0
fmt.Println("Enter a number to add: ")
fmt.Scan(&ele)
if ele==0 {
fmt.Println("Stopping!")
break
}
sli = append(sli, int(ele))
}
fmt.Println(sli)
}
The code would stop and print the slice when you enter anything other than an integer.

undefined <type float32 has no field or method sum> error.How do I fix it?

this is my program.When I run it, it gives the following error - a.sum undefined (type float32 has no field or method sum)
package main
import (
"fmt"
)
type Calculation interface {
operation(input []float32)
}
type Addition struct {
sum float32
}
func (a Addition) operation(input []float32) {
a.sum = input[0]
for _, a := range input[1:] {
a.sum += a
}
fmt.Println("Sum :", a.sum)
}
func main() {
var n int
fmt.Println("Enter the no of inputs : ")
fmt.Scanln(&n)
var input []float32
input = make([]float32 , n)
fmt.Println("Enter the numbers ")
for i:=0 ; i <n ; i++ {
fmt.Scanln(&input[i])
}
var c Calculation
i := Addition{0}
c = i
c.operation(input)
}
I have written 3 more functions Subtraction , Multiplication and Division with Addition. All of them follow similar format but those three run with out any error, Only addition is giving this error. Unable to figure out why.
Your variable a in the loop shadows the variable a representing Addition. Changing your loop to this will solve the problem:
for _, v := range input[1:] {
a.sum += v
}

Short way to apply a function to all elements in a list in golang

Suppose I would like to apply a function to every element in a list, and then put the resulting values in another list so I can immediately use them. In python, I would do something like this:
list = [1,2,3]
str = ', '.join(multiply(x, 2) for x in list)
In Go, I do something like this:
list := []int{1,2,3}
list2 := []int
for _,x := range list {
list2 := append(list2, multiply(x, 2))
}
str := strings.Join(list2, ", ")
Is it possible to do this in a shorter way?
I would do exactly as you did, with a few tweaks to fix typos
import (
"fmt"
"strconv"
"strings"
)
func main() {
list := []int{1,2,3}
var list2 []string
for _, x := range list {
list2 = append(list2, strconv.Itoa(x * 2)) // note the = instead of :=
}
str := strings.Join(list2, ", ")
fmt.Println(str)
}
This is an old question, but was the top hit in my Google search, and I found information that I believe will be helpful to the OP and anyone else who arrives here, looking for the same thing.
There is a shorter way, although you have to write the map function yourself.
In go, func is a type, which allows you to write a function that accepts as input the subject slice and a function, and which iterates over that slice, applying that function.
See the Map function near the bottom of this Go by Example page : https://gobyexample.com/collection-functions
I've included it here for reference:
func Map(vs []string, f func(string) string) []string {
vsm := make([]string, len(vs))
for i, v := range vs {
vsm[i] = f(v)
}
return vsm
}
You then call it like so:
fmt.Println(Map(strs, strings.ToUpper))
So, yes: The shorter way you are looking for exists, although it is not built into the language itself.
I've created a small utility package with Mapand Filter methods now that generics have been introduced in 1.18 :)
https://pkg.go.dev/github.com/sa-/slicefunk
Example usage
package main
import (
"fmt"
sf "github.com/sa-/slicefunk"
)
func main() {
original := []int{1, 2, 3, 4, 5}
newArray := sf.Map(original, func(item int) int { return item + 1 })
newArray = sf.Map(newArray, func(item int) int { return item * 3 })
newArray = sf.Filter(newArray, func(item int) bool { return item%2 == 0 })
fmt.Println(newArray)
}
With go1.18+ you can write a much cleaner generic Map function:
func Map[T, V any](ts []T, fn func(T) V) []V {
result := make([]V, len(ts))
for i, t := range ts {
result[i] = fn(t)
}
return result
}
Usage, e.g:
input := []int{4, 5, 3}
outputInts := Map(input, func(item int) int { return item + 1 })
outputStrings := Map(input, func(item int) string { return fmt.Sprintf("Item:%d", item) })
Found a way to define a generic map array function
func Map(t interface{}, f func(interface{}) interface{} ) []interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Slice:
s := reflect.ValueOf(t)
arr := make([]interface{}, s.Len())
for i := 0; i < s.Len(); i++ {
arr[i] = f(s.Index(i).Interface())
}
return arr
}
return nil
}
origin := []int{4,5,3}
newArray := Map(origin, func(item interface{}) interface{} { return item.(int) + 1})
You can use lo's Map in order to quickly apply a function to all elements. For example, in order to multiply by 2 and convert to string, you can use:
l := lo.Map[int, string]([]int{1, 2, 3, 4}, func(x int, _ int) string { return strconv.Itoa(x * 2) })
Then you can convert back to a comma delimited string like so:
strings.Join(l, ",")

What is the correct way to find the min between two integers in Go?

I imported the math library in my program, and I was trying to find the minimum of three numbers in the following way:
v1[j+1] = math.Min(v1[j]+1, math.Min(v0[j+1]+1, v0[j]+cost))
where v1 is declared as:
t := "stackoverflow"
v1 := make([]int, len(t)+1)
However, when I run my program I get the following error:
./levenshtein_distance.go:36: cannot use int(v0[j + 1] + 1) (type int) as type float64 in argument to math.Min
I thought it was weird because I have another program where I write
fmt.Println(math.Min(2,3))
and that program outputs 2 without complaining.
so I ended up casting the values as float64, so that math.Min could work:
v1[j+1] = math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost)))
With this approach, I got the following error:
./levenshtein_distance.go:36: cannot use math.Min(int(v1[j] + 1), math.Min(int(v0[j + 1] + 1), int(v0[j] + cost))) (type float64) as type int in assignment
so to get rid of the problem, I just casted the result back to int
I thought this was extremely inefficient and hard to read:
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
I also wrote a small minInt function, but I think this should be unnecessary because the other programs that make use of math.Min work just fine when taking integers, so I concluded this has to be a problem of my program and not the library per se.
Is there anything that I'm doing terrible wrong?
Here's a program that you can use to reproduce the issues above, line 36 specifically:
package main
import (
"math"
)
func main() {
LevenshteinDistance("stackoverflow", "stackexchange")
}
func LevenshteinDistance(s string, t string) int {
if s == t {
return 0
}
if len(s) == 0 {
return len(t)
}
if len(t) == 0 {
return len(s)
}
v0 := make([]int, len(t)+1)
v1 := make([]int, len(t)+1)
for i := 0; i < len(v0); i++ {
v0[i] = i
}
for i := 0; i < len(s); i++ {
v1[0] = i + 1
for j := 0; j < len(t); j++ {
cost := 0
if s[i] != t[j] {
cost = 1
}
v1[j+1] = int(math.Min(float64(v1[j]+1), math.Min(float64(v0[j+1]+1), float64(v0[j]+cost))))
}
for j := 0; j < len(v0); j++ {
v0[j] = v1[j]
}
}
return v1[len(t)]
}
Until Go 1.18 a one-off function was the standard way; for example, the stdlib's sort.go does it near the top of the file:
func min(a, b int) int {
if a < b {
return a
}
return b
}
You might still want or need to use this approach so your code works on Go versions below 1.18!
Starting with Go 1.18, you can write a generic min function which is just as efficient at run time as the hand-coded single-type version, but works with any type with < and > operators:
func min[T constraints.Ordered](a, b T) T {
if a < b {
return a
}
return b
}
func main() {
fmt.Println(min(1, 2))
fmt.Println(min(1.5, 2.5))
fmt.Println(min("Hello", "世界"))
}
There's been discussion of updating the stdlib to add generic versions of existing functions, but if that happens it won't be until a later version.
math.Min(2, 3) happened to work because numeric constants in Go are untyped. Beware of treating float64s as a universal number type in general, though, since integers above 2^53 will get rounded if converted to float64.
There is no built-in min or max function for integers, but it’s simple to write your own. Thanks to support for variadic functions we can even compare more integers with just one call:
func MinOf(vars ...int) int {
min := vars[0]
for _, i := range vars {
if min > i {
min = i
}
}
return min
}
Usage:
MinOf(3, 9, 6, 2)
Similarly here is the max function:
func MaxOf(vars ...int) int {
max := vars[0]
for _, i := range vars {
if max < i {
max = i
}
}
return max
}
For example,
package main
import "fmt"
func min(x, y int) int {
if x < y {
return x
}
return y
}
func main() {
t := "stackoverflow"
v0 := make([]int, len(t)+1)
v1 := make([]int, len(t)+1)
cost := 1
j := 0
v1[j+1] = min(v1[j]+1, min(v0[j+1]+1, v0[j]+cost))
fmt.Println(v1[j+1])
}
Output:
1
Though the question is quite old, maybe my package imath can be helpful for someone who does not like reinventing a bicycle. There are few functions, finding minimal of two integers: ix.Min (for int), i8.Min (for int8), ux.Min (for uint) and so on. The package can be obtained with go get, imported in your project by URL and functions referred as typeabbreviation.FuncName, for example:
package main
import (
"fmt"
"<Full URL>/go-imath/ix"
)
func main() {
a, b := 45, -42
fmt.Println(ix.Min(a, b)) // Output: -42
}
As the accepted answer states, with the introduction of generics in go 1.18 it's now possible to write a generic function that provides min/max for different numeric types (there is not one built into the language). And with variadic arguments we can support comparing 2 elements or a longer list of elements.
func Min[T constraints.Ordered](args ...T) T {
min := args[0]
for _, x := range args {
if x < min {
min = x
}
}
return min
}
func Max[T constraints.Ordered](args ...T) T {
max := args[0]
for _, x := range args {
if x > max {
max = x
}
}
return max
}
example calls:
Max(1, 2) // 2
Max(4, 5, 3, 1, 2) // 5
Could use https://github.com/pkg/math:
import (
"fmt"
"github.com/pkg/math"
)
func main() {
a, b := 45, -42
fmt.Println(math.Min(a, b)) // Output: -42
}
Since the issue has already been resolved, I would like to add a few words. Always remember that the math package in Golang operates on float64. You can use type conversion to cast int into a float64. Keep in mind to account for type ranges. For example, you cannot fit a float64 into an int16 if the number exceeds the limit for int16 which is 32767. Last but not least, if you convert a float into an int in Golang, the decimal points get truncated without any rounding.
If you want the minimum of a set of N integers you can use (assuming N > 0):
import "sort"
func min(set []int) int {
sort.Slice(set, func(i, j int) bool {
return set[i] < set[j]
})
return set[0]
}
Where the second argument to min function is your less function, that is, the function that decides when an element i of the passed slice is less than an element j
Check it out here in Go Playground: https://go.dev/play/p/lyQYlkwKrsA

Resources