6

In Mathematica there is a way to create struct-like data type:

struct[myField]=value

I want to return myStruct from a function:

getStruct[input_List] := Module[{struct},
   (*populate struct[key]=value from input*)
   Return[struct];
   ];

But when I do:

st = getStruct[myInput];
DownValues[st]

it returns nothing, because it references symbol that was created inside function (like struct$1299885). I can still access this struct with st["field"], but it's not very usefully without field list.

Basically, I want to pass structs between functions, easily get field list AND easily access values inside those fields. And no, I don't want to do this with global symbols - I want to keep everything in local scope. Is it possible with Mathematica?

I tried this approach because you can easily nest structs within each other and easily access nested fields, like st["field1"]["field2"]. I can also do this with list of rules, but nested access requires a lot of code and looks ugly for something so simple.

Edit: it seems I was missing something very simple. To get list of fields I just needed to run:

DownValues[Evaluate[st]]

Thanks, Leonid.

EvgenijM86
  • 311
  • 2
  • 5

1 Answers1

3

Much, if not all, of the desired functionality may be in the new, MMA-10 Association type. In earlier versions, I got a lot of mileage out of the following techniques:

Lists of rules can also act like structs:

ClearAll[x, y, myStruct]
myStruct = {x -> 42, y -> 47}

instead of myStruct.x, which you would do in a C-like syntax, you do x/.myStruct

In[48]:= x /. myStruct
Out[48]= 42

which can be applied to compound expressions

In[49]:= (x^2 + 3 y) /. myStruct
Out[49]= 1905

as opposed to myStruct.x ** 2 + 3 * myStruct.y, as you might have to do in C-like syntax. But, if you want to have dot-notation, and you don't use Dot elsewhere, you can do something like this:

ClearAll[Flip];
Flip[fn_] := Function[{x, y}, fn[y, x]];
Unprotect[Dot];
SetAttributes[Dot, HoldRest];
Dot[rules_, member_] := member /. rules;
Dot[rules_, member_, members__] := 
    Fold[Flip@ReplaceAll, List @@ rules, Unevaluated@{member, members}];
Protect[Dot];

and then you get (nested) dots, as in

In[50]:= myStruct.x^2 + 3 myStruct.y
Out[50]= 1905

and

In[59]:= myNewStruct = {a -> 42, b -> {c -> 47, d -> 18}}
Out[59]= {a -> 42, b -> {c -> 47, d -> 18}}

In[60]:= Sin[myNewStruct.a] + myNewStruct.b.c/N[myNewStruct.b.d]
Out[60]= 1.69459

If you have big structs, you can turn them into Dispatch tables for O(1) lookup, like this

In[62]:= {a -> 42, b -> {c -> 47, d -> 18} // Dispatch} // Dispatch
Out[62]= Dispatch[{a -> 42, b -> {c -> 47, d -> 18}}]

In[63]:= Sin[myNewStruct.a] + myNewStruct.b.c/N[myNewStruct.b.d]
Out[63]= 1.69459
Reb.Cabin
  • 8,661
  • 1
  • 34
  • 62