9
$\begingroup$

I'm looking for a way to reference an element within a List to get another element in the same parent List. I can't really see any way to do this without either being able to specify a level that is above that element in a getter function or without some kind of self-referencing construct like .this() for object-oriented ADTs.

As a minimal example, is there a way to get

listex={MemoryInUse[],f[x],MemoryInUse[],difference}

where difference=listex[[3]]-listex[[1]], or is my sole option to generate a List without these dependent elements and then Insert/Append them post-creation?

$\endgroup$
  • 3
    $\begingroup$ listex = {MemoryInUse[], f[x], MemoryInUse[], difference}; difference = listex[[3]] - listex[[1]]; listex? $\endgroup$ – Karsten 7. Oct 27 '15 at 19:01
  • 4
    $\begingroup$ Sorry, I don't understand the question. Is this a question about syntax, about how to write something concisely and conveniently? Is it about functionality, constructing a data structure you don't know how to make? What's wrong with Append? Can you describe in more details what you want to do and why you want to do it? The why will help us understand the what better. $\endgroup$ – Szabolcs Oct 27 '15 at 20:22
  • $\begingroup$ @Szabolcs, Fundamentally I was looking for simpler syntax, as I was already using what @Karsten7.'s comment suggests/mimics, and the ability have the values set on creation. I think Arnoud and WReach's answers do a good job of addressing these desires. My secondary motivation was to have these referencing cells update their values when the referenced values change, but Dynamic's witchcraft seems to be able to handle such recursive definitions as le={1,2,Dynamic[le[[1]]+le[[2]]]} flawlessly. $\endgroup$ – IPoiler Oct 28 '15 at 21:33
9
$\begingroup$

Perhaps this:

{a = 1, b = 2, c = 3, a + b + c}

(* gives {1,2,3,6} *)

So you're assigning elements of a list to a variable, and then you can use them 'later' in the list.

$\endgroup$
  • $\begingroup$ Tough choice between this answer and @WReach's, but this method was simple enough to make me feel stupid and doesn't become as complex when these self-referencing elements are riffled throughout the List. $\endgroup$ – IPoiler Oct 28 '15 at 22:04
  • $\begingroup$ You could do this minimally cleaner by using an indexed variable. i.e. {l[1]=1,l[2]=2,l[3]=3,l[1]+l[2]+l[3]} which means you just need to clear that one variable after and has the added benefit of letting you keep track of list position as you go. And if you were strict about tracking your indices, i.e. {l[1]=1,l[2]=2,l[3]=3,l[4]=l[1]+l[2]+l[3]} you'd basically have an OOP way of doing things. $\endgroup$ – b3m2a1 Dec 8 '16 at 7:30
2
$\begingroup$

Regular List can not contain references to itself. You can use the internal function Bag instead

AppendTo[$ContextPath, "Internal`"];

ClearAll[a];
a = Bag[{Random[], Random[], BagPart[a, 2] - BagPart[a, 1]}];

BagPart[a, 2] - BagPart[a, 1]
(* 0.65051 *)

BagPart[a, 3]
(* 0.65051 *)

BagPart[a, 1] = 0;
BagPart[a, 3]
(* 0.794121 *)

See also this answer.

$\endgroup$
5
$\begingroup$

It might be worthwhile to consider a construction like this:

{##, #3 - #1}&[MemoryInUse[], f[x], MemoryInUse[]]

While this does not meet the question's requirement to avoid list post-creation, there may still be some value due to the syntactic compactness.

$\endgroup$
7
$\begingroup$
listex = ReleaseHold /@ (listex = {MemoryInUse[], f[x], MemoryInUse[],
      Hold[#[[3]] - #[[1]] &@listex]})

$\ ${28548600, f[x], 28548688, 88}

Or

listex = Evaluate /@ (listex = {MemoryInUse[], f[x], MemoryInUse[], 
     Unevaluated[#[[3]] - #[[1]] &@listex]})

Real self-referencing may lead to an unexpected output:

listex = {MemoryInUse[], f[x], MemoryInUse[], #0[[1, 3]] - #0[[1, 1]]} &@Nothing

$\ ${44107848, f[x], 44107936, -72}

To understand what's going on use

listex = {Echo[MemoryInUse[], "1"], f[x], Echo[MemoryInUse[], "2"], 
    Echo[#0[[1, 3]], "3"] - Echo[#0[[1, 1]], "4"]} &@x

and check this answer.

$\endgroup$
1
$\begingroup$

This is a variant of Karsten's answer, using ReplaceAll:

listex = (listex = {MemoryInUse[], f[x], MemoryInUse[], 
 difference}) /. {difference -> (listex[[3]] - listex[[1]])}

{2083331656, f[x], 2083331744, 88}

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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