7
$\begingroup$

I have

data1 = {1, 1};
data2 = {2, 2};
datalist = {data1, data2};

I want to create a string list based on the variable names inside datalist, in this case:

{"data1", "data2"};

ToString function does not work as it makes all possible evaluations first:

ToString[datalist]

(* {{1, 1}, {2, 2}} *)

Also tried:

ToString /@ HoldForm /@ Unevaluated @ datalist

(* {{1, 1}, {2, 2}} *)

Any ideas?

$\endgroup$
  • $\begingroup$ maybe something like listnames = Flatten[StringCases[ ToString /@ {OwnValues@data1, OwnValues@data2}[[All, 1, 1]], "HoldPattern[" ~~ x__ ~~ "]" :> x]]? $\endgroup$ – kglr Mar 12 '17 at 23:33
  • $\begingroup$ Depending on what other variable names exist something based on Names["data@"] gives you a list of strings: {"data1", "data2", "datalist"}. $\endgroup$ – JimB Mar 12 '17 at 23:37
  • 1
    $\begingroup$ Variable names that hold data in the name is usually a bad idea, imho. $\endgroup$ – Marius Ladegård Meyer Mar 12 '17 at 23:43
8
$\begingroup$

In addition to Mr.Wizard's answer here is a collection of other possibilities:

data1 = {1, 1};
data2 = {2, 2};
datalist := {data1, data2};

ToString /@ Map[HoldForm, OwnValues[datalist], {3}][[1, 2]]
ToString /@ Map[Unevaluated, OwnValues[datalist], {3}][[1, 2]]
ToString /@ Thread[HoldForm[datalist] /. OwnValues[datalist]]
ToString /@ Thread[Extract[OwnValues[datalist], {1, 2}, HoldForm]]
ToString /@ Thread[Extract[OwnValues[datalist], {1, 2}, Unevaluated]]
ToString /@ Thread[Rest@Level[OwnValues[datalist], {2}, HoldForm]]
ToString /@ Thread[Rest@Level[OwnValues[datalist], {2}, Unevaluated]]
Unevaluated[Block[datalist, ToString /@ datalist]] /. OwnValues[datalist]
Cases[OwnValues[datalist], s_ :> Block[{s}, ToString@s], {3}] // Rest
Cases[OwnValues[datalist], s : {___} :> Block[s, ToString /@ s], {2}][[1]]
FirstCase[OwnValues[datalist], s : {__} :> Block[s, ToString /@ s], {}, {2}]
Cases[OwnValues[datalist], s : {___} :> ToString /@ Thread[HoldForm@s], {2}][[1]]
FirstCase[OwnValues[datalist], s : {__} :> ToString /@ Thread[HoldForm@s], {}, {2}]
{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

{"data1", "data2"}

All the above methods work correctly when datalist is empty:

datalist := {};
ToString /@ Map[HoldForm, OwnValues[datalist], {-1}][[1, 2]]
{}
$\endgroup$
  • $\begingroup$ Not quite sure the use of OwnValues here, Could you explain a bit or give a ref? the Mathematica page does not help...@Alexey $\endgroup$ – Leo1215 Mar 13 '17 at 8:53
  • 1
    $\begingroup$ @Leo1215 Here are some references in recommended order of reading: 1, 2, 3. $\endgroup$ – Alexey Popkov Mar 13 '17 at 9:19
6
$\begingroup$

You're going to first need to hold {data1,data2} unevaluated in some way; either define it first, use SetDelayed (short form :=), or use Hold. I choose :=.

data1 = {1, 1};
data2 = {2, 2};
datalist := {data1, data2};

Cases[OwnValues[datalist], x_ :> ToString@Unevaluated@x, {3}] // Rest
{"data1", "data2"}

Or using my step function:

Cases[step[datalist], x_ :> ToString@Unevaluated@x, {2}]
{"data1", "data2"}
$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.