Creating struct to initialize array of arrays with function to push elements into that array

I want to create a function to push data into struct array. Here’s my code:

mutable struct graph{T}
  data::AbstractArray{Array{T,1},1}
  # addEdge(x,y)=push!(data[x],y) that doesn't work
end

# Creating method to assigns nodes
graph(nodes::T) where T = graph{T}([[] for i=1:nodes])
newGraph=graph(5)

I get that:

julia> newGraph=graph(5)
graph{Int64}(Array{Int64,1}[[], [], [], [], []])

and I can push elements like that:

push!(graph.data[1], 3)

but I want to do it in that way:

graph.addEdge(1,3)

and later input in the same way BFS or DFS algorithm functions, something like:

graph.BFS(2)

which will print the result of BFS (“2” is the root node in that case).
Do you know the way to do this?

So the problem is that you appear to have tried defining addEdge within graph, but in Julia the only times you define a function in a struct is for some types of constructors. Also, you probably want graph to be immutable, and rather than writing AbstractArray{Array{T,1},1}, you should probably just write AbstractVector{Vector{T}}.

struct graph{T}
    data::AbstractVector{Vector{T}}
end
graph(nodes::T) where T = graph{T}([[] for i=1:nodes])
addEdge!(G, x, y)=push!(G.data[x], y)
newGraph=graph(5)
addEdge!(newGraph, 1,3)

works as you want it to. The main lesson is that Julia isn’t Java (and that’s a good thing).

No, that’s not the problem and that’s not the solution.

What do you mean? After running that code, it gave the correct result.

I don’t have problem with result. I want a way not a result.

Julia is not an object oriented language and trying to make it into one will not be fun. You can get the syntax you want with a lot of work and closures, but it is very much recommended to write idiomatic Julia code rather than hacking together Java syntax in Julia.

2 Likes

I know, If there were classes in Julia that would be easier to get this what I want.

Maybe there’s a way. I wrote something like that and it seems to behave like I want:

struct Solution{T<:Number,S<:Function}
  data::Vector{T}
  printFunction::S
end

a=Solution(Int32[1; 2; 3], function NameDoesntMatter() print("Whatever") end)
julia> a.data
3-element Array{Int32,1}:
 1
 2
 3
julia> a.printFunction()
Whatever

I’ll try to expand this.

Ok, I’ve found the answer:

struct graph{T<:Array{Array{Int64,1},1},S<:Function}
  data::T
  addEdge::S
end

root=graph([Int[] for i=1:5], function addEdge(x,y) push!(root.data[x],y) end)

Output:

julia> root=graph([Int[] for i=1:5], function addEdge(x,y) push!(root.data[x],y) end)
graph{Array{Array{Int64,1},1},typeof(addEdge)}(Array{Int64,1}[[], [], [], [], []], addEdge)

julia> root.data
5-element Array{Array{Int64,1},1}:
 []
 []
 []
 []
 []

julia> root.addEdge(1,5)
1-element Array{Int64,1}:
 5

julia> root.data
5-element Array{Array{Int64,1},1}:
 [5]
 []
 []
 []
 []

This will break if you change the name of your graph. This is a really bad idea.

1 Like
  1. This is just a try, I’m not sure if it is even functional.
  2. Why would I want to change the name of declared graph
    3)“This will break if you change the name of your graph?”
struct initGraph{T<:Array{Array{Int64,1},1},S<:Function}
  data::T
  addEdge::S
end

nodes=5

graph=initGraph([Int[] for i=1:nodes], function addEdge(x,y) push!(graph.data[x],y) end)
graph2=initGraph([Int[] for i=1:nodes], function addEdge(x,y) push!(graph2.data[x],y) end)
graph3=initGraph([Int[] for i=1:nodes], function addEdge(x,y) push!(graph3.data[x],y) end)
graph4=initGraph([Int[] for i=1:nodes], function addEdge(x,y) push!(graph4.data[x],y) end)
graph5=initGraph([Int[] for i=1:nodes], function addEdge(x,y) push!(graph5.data[x],y) end)

I am not sure if I understand your problem, the question is “do you really really want to have this graph.addEdge(1,3) syntax?” Because what you are doing works, but it does create a new closure for each graph object, and forces you to have a abstract type field in your struct what is also not very good for performance. It is the syntax the problem? Because just doing:

add_edge!(g, i, v) = push!(g.data[i], v)
add_edge!(my_graph_obj, 1, 3)

would have better performance and would be a far more “Julian” way to do it.

That’s more about what I can do with Julia types. More of experimenting. Also as I don’t create any methods for the graph there is no need to create struct in this case.
Just:

nodes=5
graph=[Int[] for i=1:nodes]
add_edge!(g, i, v) = push!(g[i], v)
add_edge!(graph, 1, 3)