This is actually a two-fold question. First: as someone coming from an OO programming background, I find Mathematica's use of lists as the basis of everything a bit annoying. So here is how a mathematica programmer (as far as I can tell) might define a graph:
graph={{1, 2, 3, 4, 5}, {1->2, 2->4, 4->4, 4->5}};
and then the programmer would just have to remember that
graph[[1]]
refers to the list of vertices and
graph[[2]]
refers to the list of edges (in this case defined as a set of rules.)
So, I was learning about the rules in Mathematica and I saw an opportunity to make my data structures a little more object-oriented feeling. I chose to define a graph something like:
graph={Verts->{1,2,3,4,5}, Edges->{1->2, 2->4, 4->4, 4->5}};
and then refer to vertices and edges (respectively) by
Verts/.graph
Edges/.graph
This can have weird side effects, however, if some other Mathematica file has defined Verts or Edges as a global variable somewhere, however, since the left hand side of the rule is not an identifier, but is itself an object.
So question 1 is this: is this a good practice, or a bad one for creating Mathematica data structures? One of the reasons I'm doing it this way is so that I can attach arbitrary properties, say colors:
AppendTo[graph, Colors->{Red, Red, Blue, Red, Red}]; (* Labels ea. vert with a color *)
and my functions don't have to know the exact order particular properties were added. For instance you might have a function GetColor defined like:
GetColor[graph_, vertIdx_]:=(Colors/.graph)[[vertIdx]];
and this is preferable, because I might not always want to have graph data structures that have Color info and so don't want to reserve a spot in the list (like graph[[[3]]]) for color information.
Second: I see that GraphEdit returns something that looks like the rules I've described above. For instance, if I execute (and draw a graph)
Needs["GraphUtilities`"];
g = GraphEdit[];
g[[2]]
I get output like:
Graph->{1->2,3->3,4->4,5->4}
which looks like a rule! So I try this:
Graph/.g[[2]]
expecting to have
{1->2,3->3,4->4,5->4}
returned. But instead the output is just
Graph
But if I instead execute
g[[2]][[1]] /. g[[2]]
I get the expected output,
{1->2,3->3,4->4,5->4}
which means that g[[2]] really is a rule, but for some reason g[[2]][[1]] (which if executed prints Graph) is not the same as typing Graph. So what the heck is g[[2]][[1]]?
It seems almost like it is a real identifier, which if so, I would like to use to solve the problems with question 1 above. Anyone know the difference, or how to type one vs. the other into Mathematica?
I cannot find anything in the documentation about any of this (or online). Thanks.