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$

3 Answers 3

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$
1
  • $\begingroup$ Thank you for the clarification. I understand the reason now. $\endgroup$ Commented Mar 22, 2012 at 9:40
10
$\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$
1
  • $\begingroup$ Thanks a lot for the suggestion. I implemented it in my code and it works perfectly. $\endgroup$ Commented Mar 22, 2012 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$
1
  • $\begingroup$ Thank you for the explanations. I didn't know there was such a command (ToHeldExpression) $\endgroup$ Commented Mar 22, 2012 at 9:42

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.