在具有保留参数的函数中键入check Symbol的快速方法

| 可以使用以下方法测试参数是否为没有显式值的Symbol:
func[s_Symbol] = ...
但是,如果函数具有Hold属性,则该模式将匹配所有Symbols,不仅是那些没有显式值的Symbols。我可以使用:
func[s_] /; Head[s] === Symbol = ...
但这会带来比我想要的更大的性能损失。为
_Symbol
添加一条规则对性能的影响很小,而appear3ѭ似乎没有任何性能损失,但是
Head[s] === Symbol
在简单函数上有相当大的开销。 ѭ5和ѭ6的测试甚至更慢。 为了明确起见,我想为
func
提供两个不同的定义,其中一个用于未分配的符号,另一个用于其他自变量。 有没有更快的方法? 时间:
f[x_] = 0;

f /@ Range@1*^6; // Timing

f[s_Symbol] = 1;

f /@ Range@1*^6; // Timing
   {0.391,空}    {0.531,空}
Remove[f]
SetAttributes[f, HoldFirst]

f[x_] = 0;

f /@ Range@1*^6; // Timing

f[s_] /; Head[s] === Symbol = 1;

f /@ Range@1*^6; // Timing
   {0.39,空}    {1.157,空}     
已邀请:
在具有
HoldFirst
属性的代码中使用模式
s_Symbol
将改善性能:
In[121]:= Remove[f]
SetAttributes[f, HoldFirst]
f[s_Symbol] /; Head[s] === Symbol = 1;
f[_] = 0;

In[125]:= f /@ Range@1*^6; // Timing

Out[125]= {1.217, Null}

In[130]:= Remove[f2]
f2[s_Symbol] = 1;
f2[_] = 0;

In[133]:= f2 /@ Range@1*^6; // Timing

Out[133]= {1.123, Null}
    
通过将保留的符号参数委托给非保留的辅助函数
g
,可以获得与最快的运行时间相当的性能:
Remove[f, g]
SetAttributes[f, HoldFirst]
f[_] = 0;
f[s_Symbol] := g[s]
g[_Symbol] = 1;
g[_] = 0;
    
您可以通过以下方法更快地获得它:
ClearAll[f];
SetAttributes[f, HoldFirst]
f[x_] = 0;
f[s_Symbol] /; OwnValues[s] =!= {} = 1;
为了进行比较,这是您使用的一种:
ClearAll[ff];
SetAttributes[ff, HoldFirst]
ff[x_] = 0;
ff[s_] /; Head[s] === Symbol = 1;
现在:
In[30]:= f /@ Range@1*^6; // Timing

Out[30]= {0.719, Null}

In[56]:= ff /@ Range@1*^6; // Timing

Out[56]= {1.25, Null}
当您的参数主要是非符号时,这将更有效,并且之所以更快,是因为您仍然可以使用
_Symbol
模式将其过滤掉。仅对于符号列表,它实际上可能会更慢:
symbTest = Table[ToExpression[\"sym\" <> ToString[i]], {i, 100000}];
MapIndexed[If[OddQ[First@#2], #1 = First@#2] &, symbTest];

In[54]:= ReleaseHold[Map[f,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[54]= {0.234,{1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,<<99964>>,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0}}

In[58]:= ReleaseHold[Map[ff,Hold[symbTest]/.OwnValues[symbTest],{2}]]//Short//Timing
Out[58]= {0.141,{0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,<<99964>>,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1}}
    

要回复问题请先登录注册