Can I redefine a list as a set of variables?

6

3

Suppose I have a list

mydata = {3, 14, 15, 92, 65}

and in some cases I want to manipulate it as a list, like for reading from and writing to a file, or for operations to be applied to all members.
But I also want to access each member individually, and I like to name the first member alice instead of mydata[[1]], and the second bob instead of mydata[[2]], and so on. Something like union in C. Can Mathematica do this?

edit (attempt to clarify, on request)

In the example I need a way to redefine mydata as

mydata = {alice, bob, cindy, dan, elise}

so that I can access members as

a = mydata[[1]]   (* assigns 3 to a *)
b = bob           (* assigns 14 to b *)

and

mydata[[2]] = 42  
elise = 100       

results in

mydata == (3, 42, 15, 92, 100}

stevenvh

Posted 2012-12-21T19:56:29.963

Reputation: 6 446

It is not clear to me from the question that you want the functionality jVincent provides below. Would you please consider making clear the behavior you expect, including assignments? – Mr.Wizard – 2012-12-22T00:01:18.580

Answers

15

For reading you can just use SetDelayed (:=). For writing you can define an UpValue for Set thus:

 mydata = {3, 14, 15, 92, 65}

 alice := mydata[[1]]
 alice /: Set[alice, value_] := mydata[[1]] = value

Then for most purposes this will work as I expect you want it to:

 alice = alice*2;
 mydata
 {6, 14, 15, 92, 65}

Even though it's already rather short code, you can automate it simply:

 SetAttributes[alias,HoldAll]
 alias[sym_,ref_]:=(
 sym/:Set[sym,value_]:=(ref=value);
 sym:=ref;)

Which would let you do the above using alias[alice,list[[1]] ]. And to assign a list of aliases to a list you can use:

SetAttributes[listAliases,HoldAll]
listAliases[list_Symbol,{names__Symbol}] /; Length[{names}] == Length[list]:=
Extract[Hold[names],#,Function[sym,alias[sym,list[[#]]],HoldAll]]&/@Range@Length@list

jVincent

Posted 2012-12-21T19:56:29.963

Reputation: 14 423

I like the alias function you added. This is exactly what I want, thanks a bunch! +1 for now (I'll wait with the accept and see if there are other ideas) – stevenvh – 2012-12-21T20:32:58.440

1Nice stuff,+1 (upvoted alread a while ago). Just for fun - here is an alternative implementation of listAliases based on Block: SetAttributes[listAliases, HoldAll]; listAliases[list_Symbol, {names__Symbol}] /; Length[{names}] == Length[list] := Block[{alias, list, Part, names}, Thread[alias[{names}, Thread[list[[Range[Length[{names}]]]]]]]]. – Leonid Shifrin – 2012-12-24T11:31:30.620

2

Here is an alternate formulation of jVincent's method. I added handling of :=, and I also clear the alias symbols before making the assignments to allow reassignment.

It seems to me that additional functionality may be appropriate to deal with changes to the master symbol definition. For example, should all the aliases be removed if mydata is cleared? I wait for a more complete question specification before addressing these. I left out the length tests as without dynamically tracking the master assignment it seems unproductive.

SetAttributes[{alias, listAliases}, HoldAll]

alias[sub_Symbol, master_Symbol][part_Integer] := (
  ClearAll @ sub;
  sub := master[[part]];
  sub /: (sub  = value_) := master[[part]]  = value;
  sub /: (sub := value_) := master[[part]] := value;
 )

listAliases[list_Symbol, names : {__Symbol}] :=
  (MapIndexed[alias[#, list][First @ #2] &, Unevaluated /@ Unevaluated @ names];)

Example:

aa = {1, 2, 3, 4, 5};
bb = {2, 3, 5, 7, 11};

listAliases[aa, {alfa, bravo, charlie, delta, echo}]

alfa += 7;

aa
{8, 2, 3, 4, 5}
listAliases[bb, {alfa, bravo, charlie, delta, echo}]

charlie += 5;

bb
{2, 3, 10, 7, 11}

Mr.Wizard

Posted 2012-12-21T19:56:29.963

Reputation: 259 163

(+1) but one important correction: it's alfa, not alpha; see here

– Jens – 2012-12-22T02:30:58.637

1@Jens Thanks; I never knew that. – Mr.Wizard – 2012-12-22T04:38:41.473

@Jens That was hardly the largest error in my post, but hopefully all is now corrected. – Mr.Wizard – 2012-12-22T04:44:48.993