6
$\begingroup$

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.

$\endgroup$
7
  • 2
    $\begingroup$ You want DownValues[Evaluate[st]]. Not sure why this was downvoted. $\endgroup$ Commented Dec 28, 2013 at 15:23
  • $\begingroup$ Thank you! This what I was looking for! $\endgroup$
    – EvgenijM86
    Commented Dec 28, 2013 at 15:31
  • $\begingroup$ @LeonidShifrin Quite a lot of downvoting on questions these days. Perhaps a hats byproduct. $\endgroup$ Commented Dec 28, 2013 at 15:37
  • $\begingroup$ @LeonidShifrin Strange, I don't see any downvotes. Actually, I only see one vote in total. $\endgroup$ Commented Dec 28, 2013 at 15:51
  • 1
    $\begingroup$ more on structs in this post mathematica.stackexchange.com/q/990/66 $\endgroup$
    – faysou
    Commented Dec 28, 2013 at 16:05

1 Answer 1

3
$\begingroup$

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
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.