11

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?

Verbeia
  • 34,233
  • 9
  • 109
  • 224
Ruben Garcia
  • 637
  • 3
  • 9

3 Answers3

10

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]
FJRA
  • 3,972
  • 22
  • 31
8

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]]
Andy Ross
  • 19,320
  • 2
  • 61
  • 93
2

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]] ]
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371