Diciness with extracting things from a Hold'd expression
Suppose I have a list of param->value rules where the params are symbols that might have values assigned to them. For example:
{a, b, c} = {1, 2, 3};
x = Hold[{a->1, b->2, c->3}];
I need the list wrapped in Hold otherwise it would evaluate to {1->1, 2->2, 3->3}. (I'm open to any alternatives to Hold there if it makes the rest of this easier.)
Now suppose I 开发者_运维技巧want to convert x into this:
{"a"->1, "b"->2, "c"->3}
The following function will do that:
f[h_] := Block[{a,b,c}, ToString[#[[1]]]->#[[2]]& /@ ReleaseHold@h]
My question: Can you write a version of f where the list of symbols {a,b,c} doesn't have to be provided explicitly?
Here is a way using Unevaluated:
In[1]:= {a, b, c} = {1, 2, 3};
In[2]:= x = Hold[{a -> 1, b -> 2, c -> 3}];
In[3]:= ReleaseHold[
x /. (symb_ -> e_) :> ToString[Unevaluated[symb]] -> e]
Out[3]= {"a" -> 1, "b" -> 2, "c" -> 3}
{a, b, c} = {1, 2, 3};
x = Hold[{a -> 1, b -> 2, c -> 3}];
f[x_] := Cases[x, HoldPattern[z_ -> y_] :>
StringTake[ToString[(Hold@z)], {6, -2}] -> y, 2];
f[x] // InputForm
Out:
{"a" -> 1, "b" -> 2, "c" -> 3}
Perhaps not very elegant, but seems to work.
This is a bit of an old question, but I think there's an answer that combines the virtues of both Andrew Moylan's answer and belisarius' answer. You really want to have lists of rules with HoldPattern
on the left-hand side, instead of lists of rules that have Hold
wrapped around the whole thing, so that you can actually use the rules without having to go through any sort of ReleaseHold
process.
In[1]:= {a, b, c} = {1, 2, 3};
Unevaluated
can also be helpful in constructing the sort of list you want:
In[2]:= x = Thread[HoldPattern /@ Unevaluated[{a, b, c}] -> Range[3]]
Out[2]= {HoldPattern[a] -> 1, HoldPattern[b] -> 2, HoldPattern[c] -> 3}
Now you can do what you want with rule replacement. It's a bit involved, but it's something I find myself doing over and over and over again. You may notice that this list of rules has almost exactly the form of a list of OwnValues
or DownValues
, so being able to manipulate it is very helpful. The trick is using HoldPattern
and Verbatim
in concert:
In[3]:= f[rules_] :=
Replace[rules,
HoldPattern[Verbatim[HoldPattern][s_Symbol] -> rhs_] :>
With[{string = ToString[Unevaluated[s]]},
string -> rhs], {1}]
The level spec on Replace
is just there to make sure nothing unexpected happens if rhs
is itself a rule or list of rules.
In[4]:= f[x] // InputForm
Out[4]= {"a" -> 1, "b" -> 2, "c" -> 3}
精彩评论