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++, 
    Defer[RGBColor] @@@ ColorData["Rainbow", 1 - i/(num - 1)]]]];
cnamelist = {};
For[i = 1, i <= num, i++, 
  AppendTo[cnamelist, StringJoin["c", ToString[i]]]];
MapThread[Set, {ToExpression[cnamelist], colorlist}];];

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.

  • $\begingroup$ 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). $\endgroup$ – Henrik Schumacher Jun 13 '18 at 17:38
  • $\begingroup$ 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. $\endgroup$ – M.O. Jun 13 '18 at 17:42
  • $\begingroup$ 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 $\endgroup$ – Henrik Schumacher Jun 13 '18 at 17:50
  • $\begingroup$ 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? $\endgroup$ – Albert Retey Jun 13 '18 at 22:51
  • $\begingroup$ 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. $\endgroup$ – 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.


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

and afterwards

Scan[Clear, cnamelist]

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

  • $\begingroup$ 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. $\endgroup$ – 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.

f[num_Integer] := Module[
  {colorlist, cnamelist},
  colorlist =
      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:


fArray[num_Integer] := Module[
  colorlist =
      Directive[Opacity[1], ColorData["Rainbow", 1 - i/(num - 1)]],
      {i, 0, num - 1}
  Evaluate[Array[c, num]] = colorlist
  • $\begingroup$ 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! $\endgroup$ – M.O. Jun 13 '18 at 18:04
  • $\begingroup$ 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. $\endgroup$ – M.O. Jun 13 '18 at 18:06

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.