I have the following problem: I would like to control evaluation of a variable that points to a list. For example, frequently in the code I have functions of the form that are supposed to work on large lists (modifying them frequently):
updateList[list_, newvalue_, index_]:= (list[[index]] = newvalue)
to be used (many times) as
list = {1, 2, 3};
While[...
updateList[list, -2, 2];
]
and I should get immediately
list = {1, -2, 3}
The problem is that the list gets evaluated immediately if one is not careful and the assignment statement fails. I have tried to solve this by defining
Attributes[updateList] = {HoldAll}
It works, but I realized that this can get very complicated since I am passing the list quite a bit around in a rather big package. Some function have Hold, some not, on some I would actually like to have the second and the third argument Holding while others not... To tell you the truth, I do not feel I have the control of this behavior; sometimes it evaluates and sometimes it does not, and it is driving me crazy.
The reason why I am doing this is to save memory. One could, of course, use the following definition
updateList[list_, newValue_, index_] := (newList = list; newList[[index]] = newvalue)
and use it like
list = updateList[list, -2, 2]
to the same effect, but this will consume quite a bit of memory (my list are huge). So I am trying to control memory usage by updating storage. I guess I am trying to use them as pointers.
A more serious example would be
updateList[list_, args__] :=
Block[{indicies, newvalues},
indicies = figureOutIndiciesToChange[args];
newvalues = figureOutValuesToChange[args];
list[[indicies]] = newvalues
];
or even a more nasty example (actually happens):
updateList[list_, args__] :=
Block[{indicies, newvalues},
indicies = figureOutIndiciesToChange[args];
nestedCallToUpdateTheList[...., list, ...];
newvalues = figureOutValuesToChange[args];
list[[indicies]] = newvalues
];
where
(* here list can be third argument, or even last *)
nestedCallToUpdateTheList[...., list_, ...] :=
While[a big loop,
list[[dynamicIndicies] = dynamicValues]];
]
So I have a principle (open) question: how to update long lists (parts of it) in the most efficient way if such lists are passed through several layers of functional calls? Is there a way to achieve this without using HoldAll? Perhaps using more direct Hold functionality? Anyway, I would like to learn how to be in control...
EDIT1: Based on the comments below, I would like to add another requirement; Assume that all this has to be done within the function. Is this possible at all? A bullet-proof way would be
updateLilst[___] := fail["please used Hold on the list argument"];
updateList[...,list_Hold,...] := do the work on the list;
Or...?
EDIT2: By the way, how to test whether an argument is evaluated in the function?
p.s. I tried with Hold, but it is tricky since it is not make the assignment with a Held variable...
list[[2]]=-2
directly to modify the list? tutorial/AddingRemovingAndModifyingListElements $\endgroup$Set[Part[list, 2], -2]
if you prefer that notation. And neither clones the list, after:list = {1, 2, 3, 4, 5}; list[[2 ;; 3]] = -1;
list will be modified solist=={1,-1,-1,4,5}
$\endgroup$