17

After playing with Mathematica's symbolic and numerical capabilities, I find it to be a decent programming language, too. However, something making it less appealing as a general-purpose language is the lack of C-like struct data type (or the record type as known in Pascal). How can I get around this problem?

felix
  • 647
  • 1
  • 6
  • 10

4 Answers4

15

Update: Mathematica 10 has introduced Association, which has many of the most important properties of a struct. (See new answer.) The original, somewhat deprecated version of this answer is below.


You can use a Mathematica rule lists to mimic a C-like struct data type. E.g.,:

person = {firstName -> "John", lastName -> "Doe"}

You can then access the record's fields by using the /. operator:

firstName /. person

yields John.

lastName /. person

yields Doe.

To update a field of a record, prepend the updated field to the list:

PrependTo[person , firstName -> "Jane"]

firstName /. person then yields Jane.

Also see the Mathematica documentation on transformation rules.

Community
  • 1
  • 1
sakra
  • 62,199
  • 16
  • 168
  • 151
  • 2
    Making a few changes using prepending means that a number of unused rules will appear in the person list. Not very efficient. – Sjoerd C. de Vries Nov 19 '11 at 16:00
  • Note that Mathematica 10 has introduced [`Association`](http://reference.wolfram.com/language/ref/Association.html), which has many of the most important properties of a `struct`. See [new answer](http://stackoverflow.com/a/33465106/330202). – Jess Riedel Nov 01 '15 at 17:47
  • If a field in the "struct" is, say, a multidimensional array, is it possibly to modify individual components of that array with `PrependTo`? – Jyrki Lahtonen Apr 12 '19 at 15:56
  • @JyrkiLahtonen Use [ReplacePart](https://reference.wolfram.com/language/ref/ReplacePart.html), i.e. `PrependTo[struct, "field" -> ReplacePart["field" /. struct, 2 -> 3.14]]` – sakra Apr 12 '19 at 16:07
  • Thanks. I'm new to this. I hate to complain, but my first impression is that this is an awfully kludgy way of going about it. Why is it not possible to do a simple assignment like `lastName/.person="Smith"` should Jane Doe marry John Smith? Not your fault, I know! – Jyrki Lahtonen Apr 12 '19 at 16:25
  • Use [Associations](https://reference.wolfram.com/language/guide/Associations.html). These let you do `struct["lastName"] = "Smith"`. This answer was written before they were introduced in Mathematica 10. Associations are pretty fast, as they are backed by a [HAMT](https://en.wikipedia.org/wiki/Hash_array_mapped_trie). – sakra Apr 12 '19 at 16:30
8

If I understand your question correctly, you can simply write things like this:

x[foo] = bar
x[bar] = baz
x[1] = 7
x[7] = 1
?x

Then to access the data for any specific index just type the same (e.g., x[1] will return 7, x[foo] will return bar).

Will Robertson
  • 62,540
  • 32
  • 99
  • 117
  • This way of doing things has one real advantage over the rule approach suggested by sakra: it allows you to mutate the "fields" of the "struct" in a straightforward way. – Pillsy Sep 22 '09 at 13:20
  • 3
    There's a problem with your answer: if a "field" is a list, its elements can't be changed individually. For example, x[foo]={1,2}; x[foo] [[1]] =3 (* attempting to change list element *) will result in an error, because x[foo] is not an Lvalue. So it still doesn't fully replace C struct functionality. – felix Sep 23 '09 at 01:43
  • 1
    You need to replace the old value completely, not just change a single value of the list: f["foo"] = {1, 2}; f["foo"] = (ReplacePart[f["foo"], 1 -> 3]) Also, I'd use strings or integers for keys, not symbols. There's also some tricky business you can do by setting UpValues for Set. – Joshua Martell Nov 25 '10 at 16:08
3

Mathematica 10 has introduced Association, which has many of the most important properties of a struct.

someData = <| "name" -> "Bob", "age" -> 23 |>

In[1]:= someData["name"]
Out[1]= Bob

In[2]:= someData["age"]
Out[2]= 23

In[3]:= someData[[2]]
Out[3]= 23

For more info, see

Community
  • 1
  • 1
Jess Riedel
  • 336
  • 3
  • 15
2

This way can work:

x[foo] = bar

x[bar] = baz

x[1] = 7

x[7] = 1

x[c] = {{1,2,3},{4,5,6}}

and also for changing the elements of a list field you can so the following:

x[c] = ReplacePart[x[c], {1, 1} -> 8]

which returns:

x[c] = {{8,2,3},{4,5,6}}
Atefeh
  • 21
  • 1