# How to map a function on a variable list

The following is just an example that captures what I want to do (more on it at the bottom).

I'm trying to do something that can be paraphrased as follows: I have a global list, say list = {0,0,1,0,0,1,1,1,1}. I have a function which can modify the global list:

f[element_] := (If[element == 1, list = Select[list, # != 1 &]]; counter++)


My problem is that when I map the function on the list, it goes through all the elements of the initial version of it, without skipping the values that have been eliminated:

counter = 0;
f /@ list;
counter
(* 9 *)


How do I get around this problem? (I'm ok with making the list locally defined)

EDIT: From the comments I gather that it might be useful to explain what I actually want to do. Well, here it is. I have a quantum system which is transformed and it may incur in errors: my list is a list of possible errors. My function looks at the errors and determines if they are correctable or not. To save time, if an error $E$ is not correctable I want to skip those errors in the list that come from composing $E$ with others.

• Is your goal to compute counter...? When you first hit an element that is 1 all the other 1s will not be selected, so what do you need the modified list for? Commented Feb 9, 2016 at 22:03
• No, this is only an example. My function does much else on other objects in the meantime. My actual list is a list of possible errors on a quantum system and my function checks if they are correctable. If one is not correctable I want it to skip checking all the ones that "include it" because they must be uncorrectable as well. Commented Feb 9, 2016 at 22:12
• Seems like your better off using Select on list rather than reassigning it lots of times inside f. Commented Feb 9, 2016 at 22:15
• I would advise (not only in Mathematica) to avoid mutating state at all cost. As others have suggested better use Select and leave the original list intact or use Sow and Reap to build a list of results if you really have to do things iteratively. Commented Feb 9, 2016 at 22:23
• So, basically, you want to stop after first 1?
– Kuba
Commented Feb 10, 2016 at 7:16

I think you are misunderstanding the nature of Map. It applies a head to a series of elements, then evaluates the complete expression. Please see my answer to Scan vs. Map vs. Apply for examples and further description.

What you want might be handled by redefining f rather than redefining list.

ClearAll[f, list, counter]

f[element_] := (If[element == 1, f[1] = "skip"]; counter++)

list = {0, 0, 1, 0, 0, 1, 1, 1, 1};

counter = 0;
f /@ list
counter

{0, 1, 2, 3, 4, "skip", "skip", "skip", "skip"}

5


After the first instance of f[1] is evaluated a new definition f[1] = "skip" is added to the rule table. Further evaluations of f[1] trigger that rule instead (because it is more specific) and do not increase the counter. The new rule could also be pattern based, e.g.:

ClearAll[f, list, counter]

f[element_] := (If[element == 1, f[x_ /; x == 1] = x]; counter++)

list = {0, 0, 1, 0, 0, 1, 1.0, 1, 1};

counter = 0;
f /@ list

{0, 1, 2, 3, 4, 1, 1., 1, 1}


This returns unmodified any elements which match the Condition x == 1, after that rule is initially set by evaluation of the third element of the list.

You may use Scan and Return.

Return from f after you reset the list.

f[element_] := (If[element == 1, list = Select[list, # != 1 &];
Return[]]; counter++;)


Then Scan the function with the Return .

Scan[f, list]

counter
(* 4 *)


Hope this helps.

• What do you modify list for?
– Berg
Commented Feb 9, 2016 at 22:25
• @Berg Using the OP's example function. Commented Feb 9, 2016 at 22:27
• Wait, it should evaluate 4 times, no? There are 4 zeros. Commented Feb 9, 2016 at 22:47
• Okay. One second. Commented Feb 9, 2016 at 22:54
• What if I have the function f return the new list and I use NestWhile on it with the condition that list not be empty? As in f[list_]:=Module[{el=First@list},If[el == 1, Return[ Select[list, # != 1 &]]]; counter++] and then use NestWhile[f,initialList,Length@#>0&] Commented Feb 9, 2016 at 23:04

A solution is to manage the loop yourself, i.e.

list = {0, 0, 1, 0, 0, 1, 1, 1, 1};

p = MapIndexed[Prepend[#2, #1] &, list];

f[{element_}] := (If[First[element] == 1, p = Select[p, First[#] != 1 &]]; counter++)

f[{}] := counter++

counter = 0;

Array[f[Cases[p, {_, #}]] &, Length[p]];

counter


9

list = Map[First, p]


{0, 0, 0, 0}