undefined attributes in an slice of node structs - go

er, I am trying to learn go by implementing a random graph. I get an error on n.value undefined (type int has no field or method value), and n.neigbours undefined (type int has no field or method neigbours). I can not understand that compilation error as i create a new slice of nodesnr size of empty nodes in the g.nodes = make([]node, g.nodesnr). What is the problem?
package main
import (
"fmt"
//"math/rand"
)
type node struct {
value int
neigbours []int
}
type edge struct {
source int
sink int
}
type graph struct {
nodesnr, edgesnr int
nodes []node
edges chan edge
}
func main() {
randomGraph()
}
func input(tname string) (number int) {
fmt.Println("input a number of " + tname)
fmt.Scan(&number)
return
}
func randomGraph() (g graph) {
g = graph{nodesnr: input("nodes"), edgesnr: input("edges")}
g.addNodes()
for i := 0; i < g.nodesnr; i++ {
fmt.Println(g.nodes[i].value)
}
//g.addEdges()
return
}
func (g *graph) addNodes() {
g.nodes = make([]node, g.nodesnr)
for n := range g.nodes {
n.value = 2
n.neigbours = nil
return
}
}
func (g *graph) addEdges() {
g.edges = make(chan edge)
for i := 0; i < g.edgesnr; i++ {
//g.newEdge()
return
}
}
/*
func (g* graph) newEdge(){
e := new(edge)
e.source, e.sink = rand.Intn(g.nodesnr), rand.Intn(g.nodesnr)
g.edges <-e*
//g.addEdge()
}
*/
func (g *graph) edgeCheck(ep *edge) string {
if ep.source == ep.sink {
return "self"
}
//if(g.neigbourCheck(g.nodes[ep.source].neigbours, ep.sink) OR g.neigbourCheck(g.nodes[ep.sink].neigbours, ep.source){
// return "present"
return "empty"
}
func (g *graph) neigbourCheck(neigbours []node, node int) bool {
for neigbour := range neigbours {
if node == neigbour {
return true
}
}
return false
}
func (g *graph) addEdge() {
e := <-g.edges
switch etype := g.edgeCheck(&e); etype {
case "present":
fallthrough
case "self":
fmt.Println("self")
//go g.newEdge()
case "empty":
//g.nodes[e.source] = append(g.nodes[e.source], e.sink),
//g.nodes[e.sink] = append(g.nodes[e.sink], e.source)
fmt.Println("empty")
default:
fmt.Println("something went wrong")
}
}
Playground

Your error lies on line 47
for n := range g.nodes
When iterating over a slice, when using only one value, that value (n) will be set to the index, which is of type int. What you need to do is to change the line to:
for _, n := range g.nodes
This means that you discard the index but put the value in n instead.
Edit
n will be a copy of the value which means any changes made to n will not affect the node in the slice. To edit the node in the slice, you should actually get the index instead of the value:
for i := range g.nodes {
g.nodes[i].value = 2
g.nodes[i].neigbours = nil
return
}

Related

how to get length of linked list in golang with recursive of method pointer?

I have a single linked list. how do I get the length of the linked list with a recursive method that had a pointer receiver?
type Node struct {
data int
next *Node
}
I had tried like this, but always return 1
func (n *Node) recursiveLength() (result int) {
if n != nil {
result += 1
n = n.next
}
return
}
Your solution is not recursive. It's have compilation error. But if we want to fix it it could be like this:
package main
import "fmt"
type Node struct {
data int
next *Node
}
func (n *Node) recursiveLength() (result int) {
if n != nil {
result += 1
n = n.next
return result + n.recursiveLength()
}
return 0
}
func main() {
x := Node{data: 0, next: &Node{data: 1, next: &Node{data: 2, next: nil}}}
fmt.Println(x.recursiveLength())
}
But this is not a good idea to write length method, It's better to change it to a function that accepts a Node and returns its length:
package main
import "fmt"
type Node struct {
data int
next *Node
}
func recursiveLength(n *Node) (result int) {
if n != nil {
n = n.next
return 1 + recursiveLength(n)
}
return 0
}
func main() {
x := Node{data: 0, next: &Node{data: 1, next: &Node{data: 2, next: nil}}}
fmt.Println(recursiveLength(&x))
}

How to convert a slice of int to a slice of string

Well, I created a slice of int like this:
list_of_id := []string {1,2,3,4}
My code would do a check if a variable in my slice (list_of_id):
func contains(s [] int, input int) bool {
for _, v := range s {
if v == input {
return true
}
}
return false
}
func main() {
list_of_id := [] int {1,2,3,4}
fmt.Println(contains(list_of_id, 1))
}
I want to create a function with the flexibility that I could input 1 or "1" as well.
My intention is to create an if else condition in which the slice of int [] int {1,2,3,4} will be converted into a slice of string [] string {"1","2","3","4"} to check again.
Anddddd, I don't know how to do so. I tried to google it out but all I found is a solution to convert this [] int {1,2,3,4} to this "{1,2,3,4}"
import "strconv"
func contains(s [] int, input interface{}) bool {
switch i := input.(type) {
case int:
for _, v := range s {
if v == i {
return true
}
}
case string:
for _, v := range s {
if strconv.Itoa(v) == i {
return true
}
}
}
return false
}
https://play.golang.org/p/02J1f77n_aM
package main
import (
"fmt"
"strconv"
)
func contains(s []int, input interface{}) bool {
var c int
var err error
switch input.(type) {
case int:
c = input.(int)
case string:
tmp := input.(string)
c, err = strconv.Atoi(tmp)
}
if err != nil {
return false
}
for _, v := range s {
if v == c {
return true
}
}
return false
}
func main() {
list_of_id := []int{1, 2, 3, 4}
fmt.Println(contains(list_of_id, 3))
fmt.Println(contains(list_of_id, 5))
fmt.Println(contains(list_of_id, "1"))
fmt.Println(contains(list_of_id, "6"))
}
Here example

Removing an item in a Linked List with Go

I want to remove a Node from a linked list in Go, and I have this struct and these methods:
type Node struct {
Next *Node
Val int
}
func (n *Node) Append(val int) {
end := &Node{Val: val}
here := n
for here.Next != nil {
here = here.Next
}
here.Next = end
}
func Remove(n *Node, val int) *Node {
head := n
for head.Next != nil {
if head.Next.Val == val {
head.Next = head.Next.Next
return head
}
head = head.Next
}
return head
}
func NewNode(val int) *Node {
return &Node{Val: val}
}
I want to remove an item like this:
n := NewNode(1)
n.Append(2)
n.Append(3)
n.Append(4)
n.Append(5)
m := Remove(n, 3)
for m != nil {
fmt.Println(n.Val)
m = m.Next
}
The items that get printed out are 3 and 5, not 1,2,4and5`. I re-implemented this code in Python and got the expected answer. What is going on in Go? I have a feeling it has to do something with pointers.
You lose the head from returning a node you use to traverse. Also you are printing out the wrong object
type Node struct {
Next *Node
Val int
}
func (n *Node) Append(val int) {
end := &Node{Val: val}
here := n
for here.Next != nil {
here = here.Next
}
here.Next = end
}
func Remove(n *Node, val int) *Node {
traverser := n
for traverser.Next != nil {
if traverser.Next.Val == val {
traverser.Next = traverser.Next.Next
return n
}
traverser = traverser.Next
}
return n
}
func NewNode(val int) *Node {
return &Node{Val: val}
}
func main() {
n := NewNode(1)
n.Append(2)
n.Append(3)
n.Append(4)
n.Append(5)
m := Remove(n, 3)
for m != nil {
fmt.Println(m.Val)
m = m.Next
}
}

How can I compare struct data and interface data in Golang?

I am trying to create a generic Binary Tree in Golang. How can I compare data from an interface and input data in the code? Here is an example of what I am trying to do. The comparison that is giving me trouble is this
} else if cur.data < data {
-
package DSAA
type TreeNode struct {
data interface{}
right *TreeNode
left *TreeNode
}
type BinarySearchTree struct {
root *TreeNode
}
func BSTCreate() *BinarySearchTree {
return &BinarySearchTree{nil}
}
func (b *BinarySearchTree) Insert(cur TreeNode, data interface{}) *BinarySearchTree {
if &cur == nil {
cur := &TreeNode{data, nil, nil}
} else if cur.data < data {
b = b.Insert(*cur.left, data)
} else {
b = b.Insert(*cur.right, data)
}
return b
}
You have some options:
1- Using runtime type switch:
package main
import (
"fmt"
)
func main() {
fmt.Println(Less(1, 2)) // true
fmt.Println(Less("AB", "AC")) // true
}
func Less(a, b interface{}) bool {
switch v := a.(type) {
case int:
w := b.(int)
return v < w
case string:
w := b.(string)
return v < w
}
return false
}
then replace } else if cur.data < data { with
} else if Less(cur.data , data) {
2- Using Comparer interface:
package main
import (
"fmt"
)
type Comparer interface {
// Less reports whether the element is less than b
Less(b interface{}) bool
}
func main() {
a, b := Int(1), Int(2)
fmt.Println(a.Less(b)) // true
c, d := St("A"), St("B")
fmt.Println(c.Less(d)) // true
}
type Int int
func (t Int) Less(b interface{}) bool {
if v, ok := b.(Int); ok {
return int(t) < int(v)
}
return false
}
type St string
func (t St) Less(b interface{}) bool {
if v, ok := b.(St); ok {
return string(t) < string(v)
}
return false
}
3- Using reflect

Compilation error in go program

here is the code and i use gccgo for compilation. this for a graph based organizer. I don't need advise on graph algorithms.
package element
import (
"fmt"
"strings"
"io"
"strconv"
)
type Node struct {
id int
name string
props map[string]string
links map[string][]*Node
}
var names = make(map[string]int , 8)
var nodes = make(map[string][]*Node , 8)
//========functions================
func new_node(Id int) *Node {
return &Node( Id, " ", nil, nil)
}
func getNode_byId(nodes []*Node, id int) *Node {
for _, node := range nodes{
if node.id == id {
return node
}
}
return nil
}
func addNode(store string, node *Node) {
nodes[store] = append(nodes[store], node)
}
func addLinkToNode(node, link *Node, property string) {
node.links[property] = append(node.links[property], link)
}
func nodeFromString(str string, typ string) {
lines := strings.Split(str, "\n")
lcount := len(lines)
if lines[0] == "[begin]" && lines[lcount] == "[end]" {
fmt.Println("common dude! something wrong with ur string")
return
}
fields := strings.Fields(lines[1])
id , _ := strconv.Atoi(fields[1])
nod := getNode_byId(nodes[typ], id )
if nod == nil { nod = new_node(id) }
addNode(typ, nod)
nod.name = typ
lines = lines[2:]
ind :=0
for index, line := range lines {
fields := strings.Fields(line)
if field := fields[0]; field[0] != '-' {
ind = index
break
}
nod.props[fields[0]] = fields[1]
}
lines = lines[ind:]
for index, line := range lines {
if line[0]!= '+' {
ind = index
break
}
pivot := strings.Index(line, " ")
field := line[0:pivot]
fields := strings.Split(line[pivot:], ",")
for _, value := range fields {
id, _ := strconv.Atoi(strings.TrimSpace(value))
var link *Node = getNode_byId(nodes[typ], id)
if link == nil { link = new_node(id) }
addNode(typ, link)
append(nod.links[field], link )
}
}
}
func equal_byId( nodeA, nodeB Node) bool {
return (nodeA.id == nodeB.id)
}
func equal_byProp( nodeA, nodeB Node, property string) bool {
return (nodeA.props[property] == nodeB.props[property])
}
//========methods on node==========
func (node Node) IsEqual_byId( comparand Node ) bool {
return equal_byId(node, comparand)
}
func (node Node) IsEqual_byProp( comparand Node, property string ) bool {
return equal_byProp(node, comparand, property)
}
func (node *Node) addLink (property string, link *Node){
addLinkToNode( node, link, property)
}
//===================
func main() {
fmt.Println("hello world")
}
and this is the error I got, I tried my best but I cannot resolve.
$ gccgo elements.go
elements.go:23:19: error: expected ‘)’
elements.go:23:34: error: expected ‘;’ or ‘}’ or newline
elements.go:23:2: error: too many values in return statement
elements.go:91:4: error: value computed is not used
I do not understand where I need to use the semi-colon and why.
The problem, I think, may be in func new_node:
return &Node( Id, " ", nil, nil)
Should be
return &Node{Id, " ", nil, nil}
See http://golang.org/ref/spec#Composite_literals
Also, I have a feeling that, in func nodeFromString (line 93-ish):
append(nod.links[field], link)
Should be:
nod.links[field] = append(nod.links[field], link)
Otherwise you'll get an error.

Resources