Container types in Go - algorithm

I am trying to familiarize myself with Go and so was trying to implements some search function but looking through the docs for the container types, none of the inbuilt type implements a contains method. Am i missing something and if not how do i go about testing for membership? Do I have to implement my own method or i have to iterate through all elements. If this is so what is the rationale behind the omission of this elementary method for container types?

The standard library's container types require you do type assertions when pulling elements out. The containers themselves have no way of doing tests for membership because they don't know the types they're containing and have no way of doing a comparison.
Ric Szopa's skip list implementation might be what you're looking for. It has a Set type which implements a Contains method.
https://github.com/ryszard/goskiplist
I've been using it in production and am quite happy with it.

Maps are a built-in type which has a "contains" construct, not a method, though.
http://play.golang.org/p/ddpmiskxqS
package main
import (
"fmt"
)
func main() {
a := map[string]string{"foo": "bar"}
_, k := a["asd"]
fmt.Println(k)
_, k = a["foo"]
fmt.Println(k)
}

With the container/list package, you write your own loop to search for things. The reasoning for not having this provided in the package is probably as Dystroy said, that would hide an O(n) operation.
You can't add a method, so you just write a loop.
for e := l.Front(); e != nil; e = e.Next() {
data := e.Value.(dataType) // type assertion
if /* test on data */ {
// do something
break
}
}
It's simple enough and the O(n) complexity is obvious.
In your review of data structures supplied with Go that support searching, don't miss the sort package. Functions there allow a slice to be sorted in O(n log(n)) and then binary searched in O(log(n)) time.
Finally as Daniel suggested, consider third-party packages. There are some popular and mature packages for container types.

Related

Are there any programming pitfalls of using a map with an empty interface as the KEY

Are there any programming pitfalls of using maps in this manner:
type Set struct {
theMap map[interface{}]struct{}
}
StringSet := NewSet("abc", "pqr")
IntSet := NewSet(1, 2)
DateSet := NewSet(time.Date(2021, 2, 15, 0, 0, 0, 0, time.UTC))
Just to be clear, I know what I'm doing is probably against the spirit of several 'best practices', but that isn't my question here. I'm specifically thinking of programming issues like memory issues due to different element sizes, increased chance of hash collisions, performance degradation due to increased type assertion, etc.
Some more info:
I need to create some 'sets' of various datatypes in my application. I see in Essential Go that the best way to use sets is to use a map with an empty struct as the value.
However, in the absence of generics, I would either need to make a new type of Set for each type of data/element which I wish to store in my sets:
type StringSet struct {
stringMap map[string]struct{}
}
type DateSet struct {
dateMap map[time.Time]struct{}
}
type IntSet struct {
intMap map[int]struct{}
}
...or, use the empty interface as the key of a hashmap:
type Set struct {
theMap map[interface{}]struct{}
}
The 2nd option works very well (you can find my complete code here), but I'm worried that I'm overlooking something obvious and will run into problems later.
Thanks for your help.

Is it possible to use only one of the return values when initializing members in Go?

I understand how to use multiple return values in go. I further understand that in most cases one of the returns is an error, so ignoring returned values can be dangerous.
Is there a way to ignore a value in struct initializer like this? The below example does not work as Split returns two values, but I am interested only in the first one. I can of course create a variable but...
someFile := "test/filename.ext"
contrivedStruct := []struct{
parentDir string
}{
{ parentDir: filepath.Split(someFile) },
}
It's not possible to use only one of the return values when initializing members in Go.
Using variables clearly expresses your intent.
Go sometimes feels like it could be more succinct, but the Go authors favoured readability over brevity.
Alternatively, use a wrapper function. There are several 'Must' wrapper functions in the standard library, like: template.Must.
func first(args ...string) string {
return args[0]
}
For your particular example, splitting paths, see filepath.Base or filepath.Dir.
No, there is no way to skip one of the returned values in structure initializer.

goLang. call ".Front()" for a string list. But returns error saying string list has no Front method

I have code like this
t := strings.FieldsFunc(value, extract_word)
fmt.Println("t:", len(t),t)
m := make(map[string]int)
for word := t.Front(); word != nil; word=word.Next(){
m[word]++
}
and it gets this error
t.Front undefined (type []string has no field or method Front)
I know list has Front() method.
http://golang.org/pkg/container/list/
but why it complains here?
so confused, need help.
thank you!
[]T is not a "list" as it's referred to in other languages (e.g. Python). In Go, it's referred to as the "Slice" http://golang.org/ref/spec#Slice_types
Its elements range from 0 to len(slice)-1, and are accessed with C-like array access notation. The "front" of the slice is generally considered slice[0], though you may consider a different index the front if you're using a slice to implement something like, e.g., a stack.
No built-in type in Go has any methods defined on it, but do have built-in functions that take them as arguments, such as len.
The package you linked to implements the List type. As the documentation at the top says "Package list implements a doubly linked list." This doubly linked list, which you can create by calling list.New(), has a Front method, among the others listed in the package documentation.
t is not a List. It is a slice of strings (slices and Lists are not the same thing). The first element of a slice is [0].
I believe the for loop you mean is this (untested):
for _, word := range t {
m[word]++
}

Is there any tangible downside to using static type constructors in go?

I've always found the package.New() syntax in go rather awkward to work with.
The suggestion is that if a package holds only a single type, using package.New() to create an instance; if multiple types exist, using package.NewBlah().
http://golang.org/doc/effective_go.html#package-names
However, this approach falls down if you if you have an existing package with a New() api, adding a new external type to the package breaks the api, because you must now rename this NewFoo(). Now you have to go and change anything that uses New(), which is deeply irritating.
...and I'm just discontent with the aesthetic of writing this:
import "other"
import "bar"
import "foo"
o := other.New() // <-- Weird, what type am I getting? No idea.
x := bar.New()
y := foo.NewFoo() // <-- Awkward, makes constructor naming look inconsistent
z := foo.NewBar()
So, recently I've been using this pattern instead:
x := foo.Foo{}.New() // <-- Immediately obvious I'm getting a Foo
y := foo.Bar{}.New() // <-- Only an additional 3 characters on NewBar{}
o := other.Foo{}.New() // <-- Consistent across all packages, no breakage on update
Where the module is defined something like this:
package foo
type Foo struct {
x int
}
func (s Foo) New() *Foo {
// Normal init stuff here
return &s // <-- Edit: notice the single instance is returned
}
type Bar struct {
}
func (Bar) New() *Bar {
return &Bar{} // <-- Edit: Bad, results in double alloc. Not like this.
}
Godoc seems to work fine with it, and it seems more obvious and consistent to me, without additional verbosity.
So, question: Is there any tangible downside to this?
Yes, it has a downside. This approach may generate unnecessary garbage - depending on how good the optimization of a specific Go compiler implementation is.
It's not terribly idiomatic and may if done badly create excess garbage as you note. Essentially you are just creating an Init method for your object. I don't use a lot of constructors myself tending to prefer having valid zero values for my objects and only using a constructor if that doesn't hold true.
In your case I think I'd just stop calling the method new and instead call it Init or Setup to better reflect what it's doing. That would avoid giving people the wrong idea about what it's doing.
Edit:
I should have been more detailed here. Calling the method Init or Setup and then using it on a Zero Value would better reflect what is going on to the consumer. eg
f := &foo{}
f.Init()
This avoids the excess garbage and gives you an initializer method as you describe.

Why does the Go image package cut+paste looping over pixels?

If you look at the image package here http://golang.org/src/pkg/image/image.go you can see that the implementation of Opaque() for every image does the same thing, differing only in the pixel-specific logic.
Is there a reason for this? Would any general solution be less efficient? Is it just an oversight? Is there some limitation (I cannot see one) to the type system that would make a polymorphic [was: generic] approach difficult?
[edit] The kind of solution I was thinking of (which does not need generics in the Java sense) would be like:
type ColorPredicate func(c image.Color) bool;
func AllPixels (p *image.Image, q ColorPredicate) bool {
var r = p.Bounds()
if r.Empty() {
return true
}
for y := r.Min.Y; y < r.Max.Y; y++ {
for x := r.Min.X; x < r.Max.X; x++ {
if ! q(p.At(x,y)) {
return false
}
}
}
return true
}
but I am having trouble getting that to compile (still very new to Go - it will compile with an image, but not with an image pointer!).
Is that too hard to optimise? (you would need to have function inlining, but then wouldn't any type checking be pulled out of the loop?). Also, I now realise I shouldn't have used the word "generic" earlier - I meant it only in a generic (ha) way.
There is a limitation to the type system which prevents a general solution (or at least makes it very inefficient).
For example, the bodies of RGBA.Opaque and NRGBA.Opaque are identical, so you'd think that they could be factored out into a third function with a signature something like this:
func opaque(pix []Color, stride int, rect Rectangle) bool
You'd like to call that function this way:
func (p *RGBA) Opaque() bool {
return opaque([]Color(p.Pix), p.Stride, p.Rect)
}
But you can't. p.Pix can't be converted to []Color because those types have different in-memory representations and the spec forbids it. We could allocate a new slice, convert each individual element of p.Pix, and pass that, but that would be very inefficient.
Observe that RGBAColor and NRGBAColor have the exact same structure. Maybe we could factor out the function for just those two types, since the in-memory representation of the pixel slices is exactly the same:
func opaque(pix []RGBAColor, stride int, rect Rectangle) bool
func (p *NRGBA) Opaque() bool {
return opaque([]RGBAColor(p.Pix), p.Stride, p.Rect)
}
Alas, again this isn't allowed. This seems to be more of a spec/language issue than a technical one. I'm sure this has come up on the mailing list before, but I can't find a good discussion of it.
This seems like an area where generics would come in handy, but there's no solution for generics in Go yet.
Why does Go not have generic
types?
Generics may well be added at some
point. We don't feel an urgency for
them, although we understand some
programmers do.
Generics are convenient but they come
at a cost in complexity in the type
system and run-time. We haven't yet
found a design that gives value
proportionate to the complexity,
although we continue to think about
it. Meanwhile, Go's built-in maps and
slices, plus the ability to use the
empty interface to construct
containers (with explicit unboxing)
mean in many cases it is possible to
write code that does what generics
would enable, if less smoothly.
This remains an open issue.

Resources