# Clear variables inside Module

I have a function that uses Module. The function takes as input a .csv that can have as many columns as it wishes to, and it will import all of them. The user just needs to call function[num], and it will import num columns of the .csv. This of course is a oversimplified version of the idea of my code. To accomplish the "unknown" number of variables I used MapThread like the following.

f[num_]:=Module[{colorlist, cnamelist},
colorlist = {};
For[i = 0, i < num, i++,
AppendTo[colorlist,
Directive[Opacity[1],
Defer[RGBColor] @@@ ColorData["Rainbow", 1 - i/(num - 1)]]]];
cnamelist = {};
For[i = 1, i <= num, i++,
AppendTo[cnamelist, StringJoin["c", ToString[i]]]];


If num is set to 7, then it creates a list colorlist={"c1", "c2" ... "c7"} and then defines the variables c1, c2... c7 with a corresponding color through MapThread.

Everything works, the issue is that c1,c2, ... c7 are now defined and I cant use MapThread again. Since its inside a function the purpose it to use it again.

I tried adding to the function in the last line the following bit

For[i = 1, i <= num, i++, Clear[cnamelist[[i]] ] ]


But it returns the error Clear::ssym: cnamelist[[i]] is not a symbol or a string.

How can I clear all the variables. I have more lists like cnamelist in my code that needs to be cleared for it to work again, but I would assume the same procedure would work.

• Use Clear[cnamelist] or Delete[cnamelist , i], if you want to delete single elements from the list (note that the list gets shorter so that enumeration changes). – Henrik Schumacher Jun 13 '18 at 17:38
• Clear[cnamelist] clears cnamelist but not the variables c1,c2, ...c7 that are inside it. Tried putting Delete[cnamelist , i] instead of Clear[cnamelist[[i]] ] in the For but nothing changed, they dont clear. – M.O. Jun 13 '18 at 17:42
• Btw.: Try to avoid AppendTo. Usually it involves copying the whole list. Just compare these timings: a = {}; Do[AppendTo[a, i], {i, 100000}]; // AbsoluteTiming b = Range[1000000]; // AbsoluteTiming – Henrik Schumacher Jun 13 '18 at 17:50
• Are there any good reasons why you want that function to define variables as a side effect instead of just returning the column data? While Mathematica does allow you to do that, it is a very unusual behavior for a function and I would consider it in almost all cases a bad idea that will almost certainly cause problems at some point. Why don't you just return the data as an array? – Albert Retey Jun 13 '18 at 22:51
• I am not sure I understood your question. The example here is like that because I followed the same procedure than a previous portion of the code. The function imports data to be plotted from a .csv. The bit here is the color portion of the plots which copies the structure (code wise) of the part that imports the data. I decided to import the data like this because each column has a different label (data means something different), and the user picks the order in which to show the data in a stacked plot. So it was very relevant to know and manage the labels because order is crucial. – M.O. Jun 14 '18 at 0:08

Ah, now I see. The problem is that Clear has attribute HoldAll. So cnamelist[[i]] won't evaluate to a String.

Try

cnamelist = StringJoin["c", ToString #] &/Range[num];


and afterwards

Scan[Clear, cnamelist]


If you want to Clear a single entry, you can use

Clear[Evaluate[cnamelist[[i]]]]

• Thank you! I am not sure what the cnamelist definition was, but if I use Scan[Clear, cnamelist] it clears all the variables inside the list!. Thank you. – M.O. Jun 13 '18 at 17:57

I'd like to suggest some changes. First, get away from For loops; use Table instead; secondly, your application of RGBColor was not accomplishing anything; third, you can provide Clear with the name of a variable as a string in order to clear it, so you can Map Clear over your list of variable names after you generate them in order to clear them; fourth, you can set a list of variables to a list of values in one go, which avoids the need for MapThread. I would also use Symbol["symbolname"] rather than ToExpression, because the latter has much broader scope and will likely be slower. Finally, I would make sure that num is an integer, just to sanitize the input.

Clear[f]
f[num_Integer] := Module[
{colorlist, cnamelist},
colorlist =
Table[
Directive[Opacity[1], ColorData["Rainbow", 1 - i/(num - 1)]],
{i, 0, num - 1}
];
cnamelist = Table["c" <> ToString[i], {i, num}];
Clear /@ cnamelist;
Evaluate[Symbol /@ cnamelist] = colorlist
]


Ultimately, I would also suggest using indexed variables (e.g. c[2]) rather than composite names (i.e. c2). The indexed variables are easier to deal with programmatically. See the modified fArray below:

Clear[fArray]

fArray[num_Integer] := Module[
{colorlist},
colorlist =
Table[
Directive[Opacity[1], ColorData["Rainbow", 1 - i/(num - 1)]],
{i, 0, num - 1}
];
Clear[c];
Evaluate[Array[c, num]] = colorlist
]

• Thanks for your reply. It's a lot of information that I will try to get through. I have to admit I am by no means an experienced Mathematica user. The rest of the code of the function is covered with For loops, I will see how I can change them to Tables. In another part of the code I have to use ToExpression[ , Hold], that took a really long time to get working so I wouldnt touch that but in this case I will follow your suggestion about MapThread. I will have to read a lot about everything you said. Thank you so much! – M.O. Jun 13 '18 at 18:04
• I decided to go the way I did with c1, c2, .... c3 because in other parts of the code I required a better differentiation of names of the variables. – M.O. Jun 13 '18 at 18:06