Testing lists in GO - arrays

I'm trying to implement a test in GO. But I'm struggling with the list's syntax inside the struct.
package primeFactor
import "testing"
var testCases = []struct {
p int
expected []int
}{
{15, [3,5]},
{26, [2,13]},
{37, [37]},
{42, [2,3,7]},
}
func TestPrimeFactor(t *testing.T) {
for _, test := range testCases {
observed := PrimeFactor(test.p)
if observed != test.expected {
t.Error("For p = %d, expected %t. Got %t.",
test.p, test.expected, observed)
}
}
}
The output error I have is:
expected ']', found ','
: expected operand, found '{'
: expected ';', found 'for'
I appreciate your help. Thanks.

Toni's answer addresses your specific problem but to address the other issue of comparing slices you'll want to use reflect.DeepEqual
Check out this example:
package main
import (
"fmt"
"reflect"
)
func main() {
observed := []int{1, 2}
expected := []int{1, 3}
if reflect.DeepEqual(observed, expected) {
fmt.Println("Slices are the same")
} else {
fmt.Println("Slices are different")
}
}
https://play.golang.org/p/_JRQ5bqmJf

Why do you wrote that in the first place? That's not Go syntax. From the spec:
A slice literal describes the entire underlying array literal. Thus, the length and capacity of a slice literal are the maximum element index plus one. A slice literal has the form
[]T{x1, x2, … xn}
So, in your case:
var testCases = []struct {
p int
expected []int
}{
{15, []int{3, 5}},
{26, []int{2, 13}},
{37, []int{37}},
{42, []int{2, 3, 7}},
}
The spec is pretty readable and less scary than one might think. You may want to give it a full look and keep it close for reference.

...and for completeness, here's just a simple example of writing your own function that your test can call to compare the slices:
func slicesMatch(a, b []int) bool {
la := len(a)
lb := len(b)
if la != lb {
return false
}
for i := 0; i < la; i++ {
if a[i] != b[i] {
return false
}
}
return true
}
View it on the Playground

Related

How to pass multidimensional array in arbitrary size as function argument in GO

I'm new to GO. There is the problem I'm facing.
The function takes a 2D array in arbitrary size as argument:
func PrintArray(a [][]string) {
for _, v1 := range a {
for _, v2 := range v1 {
fmt.Printf("%s ", v2)
}
fmt.Printf("\n")
}
}
As you can see, since the nested loop uses range. The size of the array really doesn't matter.
But when I try to call this function:
a := [3][2]string{
{"line", "tiger"},
{"cat", "dog"},
{"pigeon", "hamster"},
}
PrintArray(a[:])
It complains about:
cannot use a[:] (type [][2]string) as type [][]string in argument to PrintArray
However, it won't compile with a[:][:] either.
What is the correct way to define a multidimensional array in arbitrary size in GO lang?
In Go, array types and slice types are distinct. Pass slices to slices.
For example,
package main
import (
"fmt"
)
func main() {
a := [][]string{
{"line", "tiger"},
{"cat", "dog"},
{"pigeon", "hamster"},
}
PrintSlices(a)
}
func PrintSlices(a [][]string) {
for _, v1 := range a {
for _, v2 := range v1 {
fmt.Printf("%s ", v2)
}
fmt.Printf("\n")
}
}
Playground: https://play.golang.org/p/3mPDTIEUQmT
Output:
line tiger
cat dog
pigeon hamster
To allocate a matrix:
package main
import (
"fmt"
)
func NewMatrix(rows, cols int) [][]int {
m := make([][]int, rows)
for r := range m {
m[r] = make([]int, cols)
}
return m
}
func main() {
m := NewMatrix(3, 2)
fmt.Println(m)
}
Playground: https://play.golang.org/p/qvwQu2giRcP
Output:
[[0 0] [0 0] [0 0]]
Interesting question. This should work
a := [][]string{
{"line", "tiger"},
{"cat", "dog"},
{"pigeon", "hamster"},
}
PrintArray(a[:])
From the error messages, I would guess that arrays defined with size are of different types.
For example, if the PrintArray looks like this:
func PrintArray(a [3][2]string) {
Then you can pass it an array defined as:
a := [3][2]string.
If we vary the numbers in either the PrintArray method or a, so that they differ, we get an error message that says:
cannot use a (type [3][2]string) as type [3][1]string in argument to PrintArray

Merge two or more []map[string]interface{} types into one in Golang

I'm using Golang and for some reason, I need to merge results from different database queries, all of which return me a []map[string]interface{}
I'm thinking of Append but its just not clear enough if this is even possible.
What is the final datatype I'm looking at?
Clearly, an array of maps of interfaces with keys as strings should be able to simply 'attach' (concat, if you may) to another array of maps of interfaces with keys as strings!
So what is the mechanism to achieve this?
Even the answer is already given in the comments above i will post a short example how this can be achieved.
package main
import (
"fmt"
)
func main() {
result := []map[string]interface{}{}
mp1 := map[string]interface{}{
"one" : 1,
"two" : 2,
}
mp2 := map[string]interface{}{
"three" : 3,
"four" : 4,
}
mp3 := make(map[string]interface{})
for k, v := range mp1 {
if _, ok := mp1[k]; ok {
mp3[k] = v
}
}
for k, v := range mp2 {
if _, ok := mp2[k]; ok {
mp3[k] = v
}
}
result = append(result, mp1, mp2)
fmt.Println(result)
}
The output will be:
[map[one:1 two:2] map[three:3 four:4]]
Playground example
The other answer is correct. You could also write a helper function to avoid repetitive map merges.
// overwriting duplicate keys, you should handle that if there is a need
func mergeMaps(maps ...map[string]interface{}) map[string]interface{} {
result := make(map[string]interface{})
for _, m := range maps {
for k, v := range m {
result[k] = v
}
}
return result
}
func main() {
log.Println(`started`)
v := []map[string]interface{}{
map[string]interface{}{
`one`: 1,
`two`: 2,
},
map[string]interface{}{
`one`: `I`,
`three`: 3,
`other`: `NAN`,
},
map[string]interface{}{
`name`: `Bob`,
`age`: 300,
},
}
m := mergeMaps(v...)
log.Println(m, len(m))
}
The above solutions suggested by Endre and Kaveh both works, but it is much simpler, handy, and more optimized to use mergo when one wants to merge Go structs and maps which covers vast scenarios apart from merging map[string]interface{}
package main
import (
"fmt"
"github.com/imdario/mergo"
)
func main() {
mp1 := map[string]interface{}{
"one" : 1,
"two" : 2,
}
mp2 := map[string]interface{}{
"three" : 3,
"four" : 4,
}
mergo.Merge(&mp1, mp2) //mergo.Merge(&dest,src)
fmt.Println(mp1)
}
Output:
map[four:4 one:1 three:3 two:2]
P.S. - In Golang there is no order-preserving. Actually, iterating a map in Go is always in random order. So don't rely on a map's keys order.

Most idiomatic way to select elements from an array in Golang?

I have an array of strings, and I'd like to exclude values that start in foo_ OR are longer than 7 characters.
I can loop through each element, run the if statement, and add it to a slice along the way. But I was curious if there was an idiomatic or more golang-like way of accomplishing that.
Just for example, the same thing might be done in Ruby as
my_array.select! { |val| val !~ /^foo_/ && val.length <= 7 }
There is no one-liner as you have it in Ruby, but with a helper function you can make it almost as short.
Here's our helper function that loops over a slice, and selects and returns only the elements that meet a criteria captured by a function value:
func filter(ss []string, test func(string) bool) (ret []string) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}
Starting with Go 1.18, we can write it generic so it will work with all types, not just string:
func filter[T any](ss []T, test func(T) bool) (ret []T) {
for _, s := range ss {
if test(s) {
ret = append(ret, s)
}
}
return
}
Using this helper function your task:
ss := []string{"foo_1", "asdf", "loooooooong", "nfoo_1", "foo_2"}
mytest := func(s string) bool { return !strings.HasPrefix(s, "foo_") && len(s) <= 7 }
s2 := filter(ss, mytest)
fmt.Println(s2)
Output (try it on the Go Playground, or the generic version: Go Playground):
[asdf nfoo_1]
Note:
If it is expected that many elements will be selected, it might be profitable to allocate a "big" ret slice beforehand, and use simple assignment instead of the append(). And before returning, slice the ret to have a length equal to the number of selected elements.
Note #2:
In my example I chose a test() function which tells if an element is to be returned. So I had to invert your "exclusion" condition. Obviously you may write the helper function to expect a tester function which tells what to exclude (and not what to include).
Have a look at robpike's filter library. This would allow you to do:
package main
import (
"fmt"
"strings"
"filter"
)
func isNoFoo7(a string) bool {
return ! strings.HasPrefix(a, "foo_") && len(a) <= 7
}
func main() {
a := []string{"test", "some_other_test", "foo_etc"}
result := Choose(a, isNoFoo7)
fmt.Println(result) // [test]
}
Interestingly enough the README.md by Rob:
I wanted to see how hard it was to implement this sort of thing in Go, with as nice an API as I could manage. It wasn't hard.
Having written it a couple of years ago, I haven't had occasion to use it once. Instead, I just use "for" loops.
You shouldn't use it either.
So the most idiomatic way according to Rob would be something like:
func main() {
a := []string{"test", "some_other_test", "foo_etc"}
nofoos := []string{}
for i := range a {
if(!strings.HasPrefix(a[i], "foo_") && len(a[i]) <= 7) {
nofoos = append(nofoos, a[i])
}
}
fmt.Println(nofoos) // [test]
}
This style is very similar, if not identical, to the approach any C-family language takes.
Today, I stumbled on a pretty idiom that surprised me. If you want to filter a slice in place without allocating, use two slices with the same backing array:
s := []T{
// the input
}
s2 := s
s = s[:0]
for _, v := range s2 {
if shouldKeep(v) {
s = append(s, v)
}
}
Here's a specific example of removing duplicate strings:
s := []string{"a", "a", "b", "c", "c"}
s2 := s
s = s[:0]
var last string
for _, v := range s2 {
if len(s) == 0 || v != last {
last = v
s = append(s, v)
}
}
If you need to keep both slices, simply replace s = s[:0] with s = nil or s = make([]T, 0, len(s)), depending on whether you want append() to allocate for you.
There are a couple of nice ways to filter a slice without allocations or new dependencies. Found in the Go wiki on Github:
Filter (in place)
n := 0
for _, x := range a {
if keep(x) {
a[n] = x
n++
}
}
a = a[:n]
And another, more readable, way:
Filtering without allocating
This trick uses the fact that a slice shares the same backing array
and capacity as the original, so the storage is reused for the
filtered slice. Of course, the original contents are modified.
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
For elements which must be garbage collected, the following code can
be included afterwards:
for i := len(b); i < len(a); i++ {
a[i] = nil // or the zero value of T
}
One thing I'm not sure about is whether the first method needs clearing (setting to nil) the items in slice a after index n, like they do in the second method.
EDIT: the second way is basically what MicahStetson described in his answer. In my code I use a function similar to the following, which is probably as good as it gets in terms on performance and readability:
func filterSlice(slice []*T, keep func(*T) bool) []*T {
newSlice := slice[:0]
for _, item := range slice {
if keep(item) {
newSlice = append(newSlice, item)
}
}
// make sure discarded items can be garbage collected
for i := len(newSlice); i < len(slice); i++ {
slice[i] = nil
}
return newSlice
}
Note that if items in your slice are not pointers and don't contain pointers you can skip the second for loop.
There isn't an idiomatic way you can achieve the same expected result in Go in one single line as in Ruby, but with a helper function you can obtain the same expressiveness as in Ruby.
You can call this helper function as:
Filter(strs, func(v string) bool {
return strings.HasPrefix(v, "foo_") // return foo_testfor
}))
Here is the whole code:
package main
import "strings"
import "fmt"
// Returns a new slice containing all strings in the
// slice that satisfy the predicate `f`.
func Filter(vs []string, f func(string) bool) []string {
vsf := make([]string, 0)
for _, v := range vs {
if f(v) && len(v) > 7 {
vsf = append(vsf, v)
}
}
return vsf
}
func main() {
var strs = []string{"foo1", "foo2", "foo3", "foo3", "foo_testfor", "_foo"}
fmt.Println(Filter(strs, func(v string) bool {
return strings.HasPrefix(v, "foo_") // return foo_testfor
}))
}
And the running example: Playground
you can use the loop as you did and wrap it to a utils function for reuse.
For multi-datatype support, copy-paste will be a choice. Another choice is writing a generating tool.
And final option if you want to use lib, you can take a look on https://github.com/ledongthuc/goterators#filter that I created to reuse aggregate & transform functions.
It requires the Go 1.18 to use that support generic + dynamic type you want to use with.
filteredItems, err := Filter(list, func(item int) bool {
return item % 2 == 0
})
filteredItems, err := Filter(list, func(item string) bool {
return item.Contains("ValidWord")
})
filteredItems, err := Filter(list, func(item MyStruct) bool {
return item.Valid()
})
It also supports Reduce in case you want to optimize the way you select.
Hope it's useful with you!
"Select Elements from Array" is also commonly called a filter function. There's no such thing in go. There are also no other "Collection Functions" such as map or reduce. For the most idiomatic way to get the desired result, I find https://gobyexample.com/collection-functions a good reference:
[...] in Go it’s common to provide collection functions if and when they are specifically needed for your program and data types.
They provide an implementation example of the filter function for strings:
func Filter(vs []string, f func(string) bool) []string {
vsf := make([]string, 0)
for _, v := range vs {
if f(v) {
vsf = append(vsf, v)
}
}
return vsf
}
However, they also say, that it's often ok to just inline the function:
Note that in some cases it may be clearest to just inline the
collection-manipulating code directly, instead of creating and calling
a helper function.
In general, golang tries to only introduce orthogonal concepts, meaning that when you can solve a problem one way, there shouldn't be too many more ways to solve it. This adds simplicity to the language by only having a few core concepts, such that not every developer uses a different subset of the language.
Take a look at this library: github.com/thoas/go-funk
It provides an implementation of a lot of life-saving idioms in Go (including filtering of elements in array for instance).
r := funk.Filter([]int{1, 2, 3, 4}, func(x int) bool {
return x%2 == 0
}
Here is an elegant example of both Fold and Filter that uses recursion to accomplish filtering. FoldRight is also generally useful. It is not stack safe but could be made so with trampolining. Once Golang has generics it can be entirely generalized for any 2 types:
func FoldRightStrings(as, z []string, f func(string, []string) []string) []string {
if len(as) > 1 {//Slice has a head and a tail.
h, t := as[0], as[1:len(as)]
return f(h, FoldRightStrings(t, z, f))
} else if len(as) == 1 {//Slice has a head and an empty tail.
h := as[0]
return f(h, FoldRightStrings([]string{}, z, f))
}
return z
}
func FilterStrings(as []string, p func(string) bool) []string {
var g = func(h string, accum []string) []string {
if p(h) {
return append(accum, h)
} else {
return accum
}
}
return FoldRightStrings(as, []string{}, g)
}
Here is an example of its usage to filter out all the strings with length < 8
var p = func(s string) bool {
if len(s) < 8 {
return true
} else {
return false
}
}
FilterStrings([]string{"asd","asdfas","asdfasfsa","asdfasdfsadfsadfad"}, p)
I`m developing this library: https://github.com/jose78/go-collection. PLease try this example to filter elements:
package main
import (
"fmt"
col "github.com/jose78/go-collection/collections"
)
type user struct {
name string
age int
id int
}
func main() {
newMap := generateMapTest()
if resultMap, err := newMap.FilterAll(filterEmptyName); err != nil {
fmt.Printf("error")
} else {
fmt.Printf("Result: %v\n", resultMap)
result := resultMap.ListValues()
fmt.Printf("Result: %v\n", result)
fmt.Printf("Result: %v\n", result.Reverse())
fmt.Printf("Result: %v\n", result.JoinAsString(" <---> "))
fmt.Printf("Result: %v\n", result.Reverse().JoinAsString(" <---> "))
result.Foreach(simpleLoop)
err := result.Foreach(simpleLoopWithError)
if err != nil {
fmt.Println(err)
}
}
}
func filterEmptyName(key interface{}, value interface{}) bool {
user := value.(user)
return user.name != "empty"
}
func generateMapTest() (container col.MapType) {
container = col.MapType{}
container[1] = user{"Alvaro", 6, 1}
container[2] = user{"Sofia", 3, 2}
container[3] = user{"empty", 0, -1}
return container
}
var simpleLoop col.FnForeachList = func(mapper interface{}, index int) {
fmt.Printf("%d.- item:%v\n", index, mapper)
}
var simpleLoopWithError col.FnForeachList = func(mapper interface{}, index int) {
if index > 0 {
panic(fmt.Sprintf("Error produced with index == %d\n", index))
}
fmt.Printf("%d.- item:%v\n", index, mapper)
}
Result of execution:
Result: map[1:{Alvaro 6 1} 2:{Sofia 3 2}]
Result: [{Sofia 3 2} {Alvaro 6 1}]
Result: [{Alvaro 6 1} {Sofia 3 2}]
Result: {Sofia 3 2} <---> {Alvaro 6 1}
Result: {Alvaro 6 1} <---> {Sofia 3 2}
0.- item:{Sofia 3 2}
1.- item:{Alvaro 6 1}
0.- item:{Sofia 3 2}
Recovered in f Error produced with index == 1
ERROR: Error produced with index == 1
Error produced with index == 1
The DOC currently are located in wiki section of the project. You can try it in this link. I hope you like it...
REgaRDS...

Iterate on a golang array/slice without using for statement

Is it possible to iterate on a golang array/slice without using 'for' statement?
You could use goto statement (not recommended).
package main
import (
"fmt"
)
func main() {
my_slice := []string {"a", "b", "c", "d"}
index := 0
back:
if index < len(my_slice) {
fmt.Println(my_slice[index])
index += 1
goto back
}
}
As mentioned by #LeoCorrea you could use a recursive function to iterate over a slice. A tail recursion could prevent the stack overflow mentioned by #vutran.
package main
import "fmt"
func num(a []string, i int) {
if i >= len(a) {
return
} else {
fmt.Println(i, a[i]) //0 a 1 b 2 c
i += 1
num(a, i) //tail recursion
}
}
func main() {
a := []string{"a", "b", "c"}
i := 0
num(a, i)
}
A possibly more readable but less pure example could use an anonymous function. See https://play.golang.org/p/Qen6BKviWuE.
You could write a recursive function to iterate over the slice but why would you want to not use a for loop?
Go doesn't have different loop keywords like for or while, it just has for which has a few different forms
I also don't understand why you'd want to do this, but here is a code sample using no for loops.
package main
import "fmt"
type P struct {
Next *P
}
func (p *P) Iterate() *P {
if p.Next != nil {
fmt.Println("Saw another P")
return p.Next.Iterate()
}
return nil
}
func main() {
var z []*P
z = append(z, &P{})
z = append(z, &P{Next: z[len(z)-1]})
z = append(z, &P{Next: z[len(z)-1]})
z = append(z, &P{Next: z[len(z)-1]})
z = append(z, &P{Next: z[len(z)-1]})
z[len(z)-1].Iterate()
}
https://play.golang.org/p/CMSp6M00kR
Please note that, while it contains a slice as requested, the properties of the slice itself go completely unused.

What's the slice element access complexity in Go?

I thought it to be O(1), but this is from a pprof output:
140 140 176: var lastSB byte = s[lenSMinusOne]
88 88 177: var lastSuffixB byte = suffix[lenSuffixMinusOne]
and by average length of s is greater than length of suffix. Thus, this shows that accessing an element takes longer if the slice is bigger?
The function is:
func hasSuffix(s, suffix []byte) bool {
lenSMinusOne := len(s) - 1
lenSuffixMinusOne := len(suffix) - 1
var lastSB byte = s[lenSMinusOne]
var lastSuffixB byte = suffix[lenSuffixMinusOne]
if lenSMinusOne < lenSuffixMinusOne {
return false
} else if lastSB != lastSuffixB {
return false
} else {
for i := 0; i < lenSuffixMinusOne ; i++ {
if suffix[i] != s[lenSMinusOne-lenSuffixMinusOne+i] {
return false
}
}
}
return true
}
UPDATE:
To reproduce the results install fetch which uses go-porterstemmer fork with a large corpus(I use a 440mb file).
pprof collects samples during program execution to illuminate hotspots. Use the testing package and go test to run benchmarks.
As you should expect, the following benchmark shows that there is no difference between reading the 2nd element of a slice on average and reading the 2691st element of a slice on average, 13439773 ns/op versus 13460864 ns/op for 904,061 byte slice elements. Both benchmarks use the same underlying data arrays. Indexing a slice is O(1).
In your example, you are reading from two different underlying data arrays with different access patterns (outer versus inner loop). On modern processors, which have sophisticated memory management and optimization, you shouldn't expect the same results.
$ go version
go version devel +3ae7a530dd4e Sat Dec 28 09:37:54 2013 -0800 linux/amd64
$ go test -bench=IndexWord
904061 2 2690.8131199111563
testing: warning: no tests to run
PASS
BenchmarkIndexWordLong 100 13460864 ns/op
BenchmarkIndexWordShort 100 13439773 ns/op
ok bench 7.814s
$
.
package main
import (
"bytes"
"fmt"
"io/ioutil"
"testing"
)
var (
Words [][]byte
ShortLen = 2
)
func IndexWord(b *testing.B, words [][]byte) {
b.ResetTimer()
b.StartTimer()
var char byte
for i := 0; i < b.N; i++ {
for _, word := range words {
char = word[len(word)-1]
}
}
_ = char
}
func BenchmarkIndexWordLong(b *testing.B) {
words := make([][]byte, len(Words))
for i, word := range Words {
words[i] = word
}
IndexWord(b, words)
}
func BenchmarkIndexWordShort(b *testing.B) {
words := make([][]byte, len(Words))
for i, word := range Words {
if len(word) > ShortLen {
word = word[:ShortLen]
}
words[i] = word
}
IndexWord(b, words)
}
func init() {
// The Complete Works of William Shakespeare
// http://www.gutenberg.org/cache/epub/100/pg100.txt
text, err := ioutil.ReadFile(`/home/peter/pg100.txt`)
if err != nil {
panic(err)
}
var n, short, long int64
Words = bytes.Fields(text)
for i, word := range Words {
word = bytes.Repeat(word, 600) // Requires 4GB memory
Words[i] = word
n++
long += int64(len(word))
shortLen := ShortLen
if len(word) < ShortLen {
shortLen = len(word)
}
short += int64(shortLen)
}
fmt.Println(n, float64(short)/float64(len(Words)), float64(long)/float64(len(Words)))
}
The code for your hasSuffix function looks like a direct port from another language; it doesn't look like it is written for Go. Here's my rewrite.
func hasSuffix(s, suffix []byte) bool {
if len(s) < len(suffix) {
return false
}
s = s[len(s)-len(suffix):]
for i, x := range suffix {
if x != s[i] {
return false
}
}
return true
}
Also, Go has a bytes.HasSuffix function.
Package bytes
func HasSuffix
func HasSuffix(s, suffix []byte) bool
HasSuffix tests whether the byte slice s ends with suffix.
Slice access is O(1), but memory access on modern computers can take orders of magnitude more or less time depending on whether the value is cached. Without seeing your code, most likely this is why one memory access is slower than another.
Another possibility are that one of your slices is an array and the index is constant, meaning that bounds checking isn't necessary.

Resources