Wrapper around slice is doing weird things - go

I am probably wasting my time implementing this, but I am looking for a way to push/pop to a slice more easily, so I have this:
package h
import (
"sync"
log "github.com/sirupsen/logrus"
)
type List struct {
internalList []interface{}
mux sync.Mutex
}
func MakeList(l []interface{}) List{
return List{l, sync.Mutex{}}
}
func (l List) Add(args ...interface{}) List{
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return l;
}
func (l List) Push(v interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList);
l.mux.Unlock()
return l;
}
func (l List) Pop() interface{}{
l.mux.Lock()
length :=len(l.internalList);
log.Info("the length is:", length)
if length < 1 {
return nil;
}
last := l.internalList[length-1]
l.internalList = l.internalList[:length-1]
l.mux.Unlock()
return last;
}
func (l List) GetLength() int {
return len(l.internalList);
}
func (l List) Shift() interface{} {
l.mux.Lock()
if len(l.internalList) < 1 {
return nil;
}
first := l.internalList[0];
l.internalList = l.internalList[1:]
l.mux.Unlock()
return first;
}
func (l List) Unshift(v interface{}){
l.mux.Lock()
l.internalList = append([]interface{}{v}, l.internalList...)
l.mux.Unlock()
}
func (l List) GetValue() []interface{}{
return l.internalList
}
and then I use it like so:
package main
import (
"github.com/sirupsen/logrus"
"huru/h"
"huru/utils"
)
func main(){
x := h.List{}
x.Push(3)
logrus.Info("value:",x.GetValue())
logrus.Info("len:",x.GetLength());
logrus.Info(x.Pop());
}
but the weird thing is I get this:
INFO[0000] internal:[3]
INFO[0000] value:[]
INFO[0000] len:0
INFO[0000] the length is:0
INFO[0000] <nil>
I have no idea why 3 gets added to the slice, but then the slice length mysteriously goes to zero and when I pop() I get nil. Anybody know why that's happening?
Given the existing answer, I am wondering if there is a difference between:
func (l *List) Add(args ...interface{}) *List {
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return l;
}
func (l *List) Push(v interface{}) *List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList)
l.mux.Unlock()
return l
}
and
func (l *List) Add(args ...interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, args...)
log.Info(l.internalList)
l.mux.Unlock()
return *l;
}
func (l *List) Push(v interface{}) List {
l.mux.Lock()
l.internalList = append(l.internalList, v)
log.Info("internal:",l.internalList)
l.mux.Unlock()
return *l
}

Since your methods are mutating the data, they need to use pointer receivers:
func (l *List) Push(v interface{}) List {
...
}
Otherwise, the state will be updated on the copy of the struct, and lost after that.
More on that in Effective Go
Update: I noticed that you return the updated value from your methods. If the copy is what you actually want, you need to keep the value receivers as they are now, but then use the returned values in your calling code as well:
x = x.Push(3)

Related

Peeking into the top of the Priority Queue in Go?

I was trying to implement a sample program using heap, and I am able to Push and Pop from the Heap. I was able to implement the Push and Pop methods and use them as follows:
import "container/heap"
type Meeting struct {
start int
end int
}
func NewMeeting(times []int) *Meeting {
return &Meeting{start: times[0], end: times[1] }
}
type PQ []*Meeting
func (pq PQ) Len() int {
return len(pq)
}
func (pq PQ) Less(i, j int) bool {
return pq[i].end < pq[j].end
}
func (pq PQ) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
}
func (pq *PQ) Push(x interface{}) {
item := x.(*Meeting)
*pq = append(*pq, item)
}
func (pq *PQ) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
old[n-1] = nil // avoid memory leak
*pq = old[0 : n-1]
return item
}
func minMeetingRooms(intervals [][]int) int {
pq := make(PQ, 0)
heap.Init(&pq)
heap.Push(&pq, NewMeeting([]int{1, 3}))
heap.Push(&pq, NewMeeting([]int{1, 2}))
fmt.Println(heap.Pop(&pq).(*Meeting)) // I would like to log this without popping prom the Queue
return 0
}
Please see the comment in the code snippet in the minMeetingRooms function.
I would like to log the top of the Priority Queue, without actually popping it. How can I go that?
You can "peek" the element that pop() will return by returning the first element of the underlying array. (i.e. pq[0])
fmt.Println(pq[0])
you need to use the first element to peek

How to embed and override a struct in Go

I am constructing the min/max heaps of ints to satisfy the interface from container/heap.
The min heap works well such as
type MinHeapInt []int
func (h MinHeapInt) Len() int {
return len(h)
}
func (h MinHeapInt) Less(i, j int) bool {
return h[i] < h[j]
}
func (h MinHeapInt) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
func (h *MinHeapInt) Peek() interface{} {
return (*h)[0]
}
func (h *MinHeapInt) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *MinHeapInt) Pop() interface{} {
length := len(*h)
res := (*h)[length - 1]
*h = (*h)[0 : length - 1]
return res
}
Now I am trying to develop the max heap by only overriding the Less method.
The first solution does not work since it cannot find the array
type MaxHeapInt struct {
MinHeapInt
}
func (h MaxHeapInt) Less(i, j int) bool {
return h[i] > h[j]
}
The second solution only keeps the Less method.
type MaxHeapInt MinHeapInt
func (h MaxHeapInt) Less(i, j int) bool {
return h[i] > h[j]
}
Wonder if there is anyway to get around. Thanks!
Your first solution is trying to index the MaxHeapInt struct, not the MinHeapInt slice.
type MaxHeapInt struct {
MinHeapInt
}
func (h MaxHeapInt) Less(i, j int) bool {
return h.MinHeapInt[i] > h.MinHeapInt[j]
}
If you want them to be initialized the same, then create a partial heap implementation, and wrap in the desired struct (similar to the wrapper example in the sort package).
type Max struct{ IntHeap }
func (h Max) Less(i, j int) bool {
return h.IntHeap[i] > h.IntHeap[j]
}
type Min struct{ IntHeap }
func (h Min) Less(i, j int) bool {
return h.IntHeap[i] < h.IntHeap[j]
}
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Peek() interface{} { return (*h)[0] }
func (h *IntHeap) Push(x interface{}) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() interface{} {
length := len(*h)
res := (*h)[length-1]
*h = (*h)[0 : length-1]
return res
}
// Now these can be initialized like
// Min{IntHeap{1, 2, 3}}
// Max{IntHeap{1, 2, 3}}

Golang container/list creating a FindAll function

I was wondering if this is the way to create and pass 'generic'(yeah I know, a sensitive word in GoLang) lists to a FindAll function.
Here's my attempt:
package main
import (
"container/list"
"fmt"
"strings"
)
func FindAll(lst *list.List, p func(interface{}) bool) *list.List {
ans := list.New()
for i := lst.Front(); i != nil; i = i.Next() {
if p(i.Value) {
ans.PushBack(i.Value)
}
}
return ans
}
func ConvertToInt(p func(int) bool) func(interface{}) bool {
return func(v interface{}) bool {
if value, ok := v.(int); ok {
if p(value) {
return true
} else {
return false
}
} else {
return false
}
}
}
func IsEven(n int) bool {
if n%2 == 0 {
return true
}
return false
}
func ConvertoString(p func(s string) bool) func(interface{}) bool {
return func(v interface{}) bool {
if value, ok := v.(string); ok {
if p(value) {
return true
} else {
return false
}
} else {
return false
}
}
}
func IsHello(str string) bool {
if strings.ToLower(str) == "hello" {
return true
} else {
return false
}
}
func main() {
fmt.Println("Find All Programs!\n\n")
lsti := list.New()
for i := 0; i < 11; i++ {
lsti.PushBack(i)
}
ansIsEven := FindAll(lsti, ConvertToInt(IsEven))
for i := ansIsEven.Front(); i != nil; i = i.Next() {
if value, ok := i.Value.(int); ok {
fmt.Printf("Found even: %d\n", value)
} else {
fmt.Println("Huh! What's that?")
}
}
}
I've been playing with this for a while and thought I'd better get the advice of the Go experts before I convince myself its correct.
The code as-is is pretty fine, but you should ask your self 2 questions:
1. Why shouldn't you use a typed slice? (interface{} performance is slow compared to the explicit type, although it will greatly improve in Go 1.7)
2. Would it be better to implement your specific type as a linked list?
Something like this can be much more efficient:
type IntList []int
func (l IntList) Filter(fn func(v int) bool) IntList {
var o IntList
for _, v := range l {
if fn(v) {
o = append(o, v)
}
}
return o
}
There's almost always a better alternative to container/list, however it all depends on your use case.

Priority queue and heap

I'm trying to implement a priority queue based on the example provided in the documentation.
Docs: priorityQueue
In short it looks like this (not everything is included):
package pq
type Item struct {
container interface{}
priority int
index int
}
type PriorityQueue []*Item
func NewItem(value interface{}, prio int) *Item {
return &Item {container: value, priority: prio}
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority > pq[j].priority
}
func (pq *PriorityQueue) Swap(i, j int) {
(*pq)[i], (*pq)[j] = (*pq)[j], (*pq)[i]
(*pq)[i].index = i
(*pq)[j].index = j
}
func (pq PriorityQueue) Push(x interface{}) {
fmt.Printf("adr: %p\n", &pq)
n := len(pq)
item := x.(*Item)
item.index = n
pq = append(pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
itm := old[n - 1]
itm.index = -1
*pq = old[0 : n-1]
return itm.container
}
The main.go file:
func main() {
q := pq.PriorityQueue{}
heap.Init(q)
fmt.Printf("\nAdr: %p\n", &q)
q.Push(pq.NewItem("h", 2))
for i := 0; i < 5; i++ {
item := pq.NewItem("test", i * 13 % 7)
heap.Push(q, item)
}
for q.Len() > 0 {
fmt.Println("Item: " + heap.Pop(q).(string))
}
}
As you can see when comparing to the example I do not use pointers since doing that will give me a compile error telling me that my priority queue does not implement the interface properly.
This leaves me with the following problem when I do:
heap.Push(q, item)
that the item is not appended to the queue.
I've tried to write out the queues pointer address and it shows different addresses. This explains why it does not work, but souldn't slices not be reference types a long with maps?
And more specificly: How do i solve my problem?
Hope you can help!
Edit: Added full code and error: cannot use q (type pq.PriorityQueue) as type heap.Interface in function argument:
pq.PriorityQueue does not implement heap.Interface (Pop method has pointer receiver)
As the example code shows, the Push method must have a pointer receiver.
The trick is that all the calls to heap.XXX functions, require that you pass your heap in as a pointer (e.g.: heap.Init(&pq)). This is not the case in the code you posted. Here is a working version of your code. You can run it on the Go playground.
Note that in this code, I explicitly initialize the queue as a pointer: q := new(PriorityQueue). And this is what I pass in to all the heap functions.
The confusion here arises mostly because you are essentially implementing 2 interfaces.
The heap.Interface and the sort.Interface (The latter is part of the prior's type definition). But the sort interface is fine with non-pointer receivers, while the other one is not.
package main
import "fmt"
import "container/heap"
func main() {
q := new(PriorityQueue)
heap.Init(q)
fmt.Printf("\nAdr: %p\n", &q)
q.Push(NewItem("h", 2))
for i := 0; i < 5; i++ {
heap.Push(q, NewItem("test", i*13%7))
}
for q.Len() > 0 {
fmt.Println("Item: " + heap.Pop(q).(string))
}
}
type Item struct {
container interface{}
priority int
index int
}
type PriorityQueue []*Item
func NewItem(value interface{}, prio int) *Item {
return &Item{container: value, priority: prio}
}
func (pq PriorityQueue) Len() int {
return len(pq)
}
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority > pq[j].priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
fmt.Printf("adr: %p\n", pq)
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
itm := old[n-1]
itm.index = -1
*pq = old[0 : n-1]
return itm.container
}

GoLang: Allocating Slice of Slices in functions results in index out of range

I've been trying some things out in Go and I've hit a problem that I can't figure out.
package main
import "fmt"
import "strconv"
func writeHello(i int, ) {
fmt.Printf("hello, world "+strconv.Itoa(i)+"\n")
}
type SliceStruct struct {
data [][]int;
}
func (s SliceStruct) New() {
s.data=make([][]int,10);
}
func (s SliceStruct) AllocateSlice(i int) {
s.data[i]=make([]int,10);
}
func (s SliceStruct) setData(i int, j int, data int) {
s.data[i][j] = data;
}
func (s SliceStruct) getData(i int, j int) int {
return s.data[i][j]
}
func useSliceStruct(){
sliceStruct := SliceStruct{};
sliceStruct.New();
for i := 0; i < 10; i++ {
sliceStruct.AllocateSlice(i);
for j:=0; j<10; j++ {
sliceStruct.setData(i,j,i);
writeHello(sliceStruct.getData(i,j));
}
}
}
func dontUseSliceStruct(){
data:=make([][]int,10);
for i := 0; i < 10; i++ {
data[i]=make([]int,10);
for j:=0; j<10; j++ {
data[i][j] = i;
writeHello(data[i][j]);
}
}
}
func main() {
dontUseSliceStruct();
useSliceStruct();
}
When it gets to the function useSliceStruct, the code fails at the first call to AllocateSlice() with an index out of range error.
As far as I can tell the code for the two methods does idential things. So what am I missing?
DOH, just worked it out.
I wasn't using a reference to the struct in the function declarations.
func (s SliceStruct)
Should have been
func (s *SliceStruct)

Resources