# Cannot assign variable value inside Do Loop

This is more of a conceptual problem.

Suppose I have three lists.

x1 = {1, 2, 9, 10};
x2 = {5, 6, 7};
x3 = {9, 10, 13};


Now, I wish to keep only the first two elements of each list. More precisely, I want

x1= {1, 2};
x2 = {5, 6};
x3 = {9, 10};


One easy way to do is,

x1=x1[[{1,2}; x2=x2[[{1,2}]]; x3=x3[[{1,2}]];


So far, it is okay. But it won't work if I try to do the same using the Do[] loop. For example,

Do[i=i[[{1,2}]],{i,{x1,x2,x3}];


do not assign new values to x1,x2,x3.

I also tried,

(#=#[[{1,2}]])&/@{x1,x2,x3}


But it didn't work.

I don't understand the reason behind this. What will be the correct way to assign variables/lists in a Do[] loop?

• You can use #[[{1, 2}]] & /@ {x1, x2, x3} Sep 1, 2021 at 17:48
• Yes, but I want to assign the new list of variables into x1, x2, x3. Your code extracts the first two elements but won't store them in x1, x2, x3. Sep 1, 2021 at 17:53
• How about you create a function say f[x_List]:=x[[{1,2}]]; then use x1 = f[x1] Sep 1, 2021 at 18:25

Mathematica is a term rewriting system. It will replace x1, x2, x3 by their values as soon as possible. One solution is:

{x1,x2,x3} = #[[{1,2}]]&/@{x1,x2,x3}


We can make it shorter as:

{x1, x2, x3} //= #[[{1, 2}]] & /@ # &


Here //= is the "apply to" assignment operator. Basically x //= f is shorthand for x=f[x]. Because {x1,x2,x3} appear on the left side of the assignment they won't be replaced by their values (due to the HoldFirst attribute of assignment), and the proper assignment will take place.

• I didn't know this //=. Thanks for pointing this out. Sep 1, 2021 at 18:33
• You can also obtain the assignments with precise evaluation control (eg. using the Hold, Release :> operators) for example as Hold[z = z[[{1, 2}]]] /. {z :> x1} , but that seems rather tedious and to go against "the grain" of the language, so to speak. Sep 1, 2021 at 18:40