2012-01-06 29 views
7

简单的问题,因为这样如何删除多余的映射时的函数列表

Clear[a, b, c, d, e, f]; 
lst = {{a, b}, {c, d}, {e, f}}; 

列表,并假设我已经定义了这样的功能{}:

foo[x_,y_]:=Module[{},...] 

而且我想这一功能应用到列表中,所以如果我型

Map[foo, lst] 

这给

{foo[{a, b}], foo[{c, d}], foo[{e, f}]} 

我希望它出来作为

{foo[a, b], foo[c, d], foo[e, f]} 

所以它的工作原理。

这样做的最好方法是什么?假设我不能修改函数foo []定义(说它是内置的)

只有2种方式,我知道现在是

Map[foo[#[[1]], #[[2]]] &, lst] 
{foo[a, b], foo[c, d], foo[e, f]} 

(工作量太大),或

MapThread[foo, Transpose[lst]] 
{foo[a, b], foo[c, d], foo[e, f]} 

(少打字,但需要先转位)

问题:还有其他更好的方法可以做到吗?我查看了其他Map和它的朋友,我看不到一个功能比我更直接。

+1

[相关](http://stackoverflow.com/q/5746717/499167)问题:**将列表应用于Mathematica中的参数** – tomd 2012-01-07 00:43:18

回答

14

您在Level 1或其缩写形式需要Apply@@@

[email protected]@@lst  
{foo[a, b], foo[c, d], foo[e, f]} 
7

一种可能的方式是从Listlst每个元素的头更改为foo

foo @@ # & /@ lst 
{foo[a, b], foo[c, d], foo[e, f]} 
4

一些更多选择的可能性:

This one i是尤达答案的一个更详细的版本。它在列表lst只(用头foo替换头List)的1级适用foo

Apply[foo, lst, {1}] 

这确实是相同的,但在列表lst(基本上是安德烈的回答)映射Apply

Map[Apply[foo, #] &, lst ] 

而这只是替换模式列表[X__]以foo在1级[X]:

Replace[lst, List[x__] -> foo[x], 1] 
6

只是为了报告的两种方法(@@@@@ # & /@)令人费解的性能测试:

 T = RandomReal[{1,100}, {1000000, 2}]; 

     H[F_Symbol, T_List] := 

        [email protected][F @@@ T;]/[email protected][F @@ # & /@ T;] 

     Table[{ToString[F], H[F, T]}, {F, {Plus, Subtract, Times, Divide, Power, Log}}] 

Out[3]= {{"Plus",  4.174757}, 
     {"Subtract", 0.2596154}, 
     {"Times", 3.928230}, 
     {"Divide", 0.2674164}, 
     {"Power", 0.3148629}, 
     {"Log",  0.2986936}} 

这些结果不是随机的,而是大致比例非常不同的数据大小。

@@@是更快Subtract大约3-4次,DividePowerLog@@ # & /@是更快PlusTimes引起另一个问题,这(为一个可以相信)有可能会稍微
通过澄清4倍以下评价:

[email protected]{Plus, Subtract, Times, Divide, Power, Log} 

只有PlusTimes有属性FlatOrderless,之间的休息,而只有Power(这似乎相对最有效)也有一个属性OneIdentity

编辑

一个可靠的解释观测到的性能提升(感谢列昂尼德·希夫林的言论)应沿着不同的路线走。

默认情况下有MapCompileLength -> 100,因为我们可以检查评估SystemOptions["CompileOptions"]。 要重置地图autocompilation我们可以评估:

SetSystemOptions["CompileOptions" -> "MapCompileLength" -> Infinity] 

现在我们可以通过评估一次我们H测试的两种方法相对性能 - 对相关符号的性能测试功能列表:

  Table[{ToString[F], H[F, T]}, {F, {Plus, Subtract, Times, Divide, Power, Log}}] 

Out[15]= {{"Plus",  0.2898246}, 
      {"Subtract", 0.2979452}, 
      {"Times",  0.2721893}, 
      {"Divide", 0.3078512}, 
      {"Power",  0.3321622}, 
      {"Log",  0.3258972}} 

有了这些结果,我们可以得出结论,一般来说尤达的方法(@@@)是最有效的,而由Andrei提供的方法在PlusTimes的情况下更好,因为自动编译的Map允许更好的p (@@ # & /@)的性能。

+3

如果我们回想到'Map'可以自动编译时, 'Apply'可以编译为3个头:'Plus','Times'和'List'。 OTOH,'@@@'不会自动编译。由于'@@#&/ @'构造中的自动合并,并且因为您的输入是一个大型打包数组(允许从自动合成中获益) – 2012-01-07 06:38:07

+1

也可以看到'Plus'和'Times'的效率提升另请参见此答案我的:http://stackoverflow.com/questions/6405304/memory-use-of-apply-vs-map-virtual-memory-use-and-lock-ups/6408489#6408489,和它下面的评论,为有关类似事宜的更多讨论。 – 2012-01-07 13:00:37

+0

@Leonid谢谢你有趣的链接和评论。事实上,当我在'T1 = FromPackedArray [T]上评估我的'H'函数时,'Plus'和'Times'的相对效率大约减慢了2倍,而另一个函数只有几个百分点,但是'Map 'Plus'和'Times'的速度几乎快两倍。这种影响的原因显然是自动合成。另一方面,关于相关职能属性的评论仍然有效,我希望不应有任何误解。 – Artes 2012-01-07 19:49:57

3

Apply[]的答案是现货,并且是做正确的事,但你想干什么,用Sequence[]头更换List[]头,即List[List[3,5],List[6,7]]应该成为List[Sequence[3,5],Sequence[6,7]]

如果删除任何参数列表的头部,序列头就是自然保留的,所以Delete[Plus[3,5],0]Delete[{3,5},0]Delete[List[3,5],0]都会产生Sequence[3,5]

所以[email protected][#,0]&/@{{a, b}, {c, d}, {e, f}}会给你一样的[email protected]@@{{a, b}, {c, d}, {e, f}}

或者,foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}}也做同样的事情。

+1

我不同意他希望将'List [List [] ..]'变成List [Sequence [...] ..]的陈述。更准确地说,他希望'List [f [...] ..]',即他想将内部列表的头部改为'f'。 – rcollyer 2012-01-07 02:21:30

+0

我同意这是他最终“想要”的。我的意思是从某种意义上说“你想做的事情是......”;-)对于混淆,我很抱歉。要进入List [f [Sequence [...]],...],他需要一种将列表列表转换为序列列表的方法。在内部应用。 – 2012-01-07 03:53:08