11
$\begingroup$

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?

$\endgroup$
8
$\begingroup$

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]]
$\endgroup$
  • $\begingroup$ Thank you for the clarification. I understand the reason now. $\endgroup$ – Ruben.Garcia Mar 22 '12 at 9:40
9
$\begingroup$

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]
$\endgroup$
  • $\begingroup$ Thanks a lot for the suggestion. I implemented it in my code and it works perfectly. $\endgroup$ – Ruben.Garcia Mar 22 '12 at 9:40
2
$\begingroup$

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]] ]
$\endgroup$
  • $\begingroup$ Thank you for the explanations. I didn't know there was such a command (ToHeldExpression) $\endgroup$ – Ruben.Garcia Mar 22 '12 at 9:42

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.