# MapThread gives different results from ToExpression when trying to assign variables from a list

I have the following data set:

data = {{"Jakarta","Surabaya","Bandung"},{1,2,3}}


and I'd actually like to assign the numerical values to the categorical data so that Jakarta = 1, Surabaya = 2 and Bandung = 3.

If I use MapThread[Set, {ToExpression[data[[1]]], data[[2]]}]it works fine but when I try to assign the variables individually I keep on getting error messages:

ToExpression[data[[1, 1]]] = data[[2, 1]]
Set::write: "Tag ToExpression in ToExpression[Jakarta] is Protected."


However, ToExpression[data[[1,1]] works fine

May I know why my second approach is not working?

-

I believe it is because Set has attribute HoldFirst. The FullForm of what you are attempting would look like...

Set[ToExpression[data[[1,1]]],1]


The ToExpression doesn't get a chance to evaluate before trying to assign the value. You can use Evaluate if you insist on doing it this way.

Evaluate[ToExpression[data[[1, 1]]]] = data[[2, 1]]

-
Thank you for the clarification. I understand the reason now. –  Ruben.Garcia Mar 22 '12 at 9:40

I think avoiding ToExpression is important, so here is a solution using Symbol:

MapThread[With[{var = (Clear[#1]; Symbol[#1])}, var = #2] &, data]


I use Clear to be sure that the symbol has not a previous value defined, which would generate an assigment error.

You can also use Evaluate instead With as @Andy answer:

MapThread[(Clear[#1]; Evaluate[Symbol[#1]] = #2) &, data]

-
Thanks a lot for the suggestion. I implemented it in my code and it works perfectly. –  Ruben.Garcia Mar 22 '12 at 9:40

Since Set attempts to assign to the object on the LHS itself, unless that object has head List, you are attempting to assign a value to ToExpression[data[[1, 1]]] just as the error message informs you.

Also, you will have a problem if your symbol names already have a value when you try your MapThread method. You need a way to get and hold the unevaluated symbol and then pass it to Set. This can be done with ToHeldExpression (or MakeExpression) as follows:

MapThread[
Set @@ Append[ToHeldExpression@#, #2] &,
data
]


This works by building the arguments for Set inside Hold and then passing them to Set with Apply (@@).

Doing this for a single element:

Set @@ Append[ToHeldExpression[ data[[1, 1]] ], data[[2, 1]] ]

-
Thank you for the explanations. I didn't know there was such a command (ToHeldExpression) –  Ruben.Garcia Mar 22 '12 at 9:42