简单的问题,给出一个像这样的列表
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 []定义(比如它是内置函数)
我现在只知道两种方式
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]}
(减少输入,但需要先转置)
问题:还有其他更好的方法吗?我看了看其他地图和它的朋友,我看不到比我的更直接的功能。
答案 0 :(得分:14)
您需要Apply
的{{1}}或其简短形式Level
@@@
答案 1 :(得分:7)
一种可能的方法是将lst
的每个元素的头部从List
更改为foo
:
foo @@ # & /@ lst
{foo[a, b], foo[c, d], foo[e, f]}
答案 2 :(得分:6)
只是报告两种方法(@@@
,@@ # & /@
)的令人费解的性能测试:
T = RandomReal[{1,100}, {1000000, 2}];
H[F_Symbol, T_List] :=
First@AbsoluteTiming[F @@@ T;]/First@AbsoluteTiming[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
,Divide
,Power
, Log
大约快3-4倍,而@@ # & /@
的速度提高4倍Plus
和Times
引发了另一个问题,(人们可以相信)可能会略有问题
通过以下评估澄清:
Attributes@{Plus, Subtract, Times, Divide, Power, Log}
只有Plus
和Times
具有Flat
和Orderless
属性,而其余只有Power
(这看起来相对效率最高)也有属性OneIdentity
。
修改强>
对观察到的性能提升的可靠解释(感谢Leonid Shifrin的评论)应该采用不同的方式。
默认情况下,MapCompileLength -> 100
可以检查评估SystemOptions["CompileOptions"]
。
要重置Map的自动编译,我们可以评估:
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}}
有了这些结果,我们可以得出结论,一般来说Yoda的方法(@@@
)是最有效的,而Andrei提供的方法在Plus
和Times
由于自动的情况下更好Map
汇编,可以更好地表现(@@ # & /@
)。
答案 3 :(得分:4)
还有一些可供选择的可能性:
这是yoda答案的更详细版本。它仅在foo
列表的第1级应用lst
(将头部List
替换为头部foo
):
Apply[foo, lst, {1}]
这样做相同,但将Apply
映射到列表lst
(基本上是Andrei的答案):
Map[Apply[foo, #] &, lst ]
这只是用级别1的foo [x]替换模式List [x__]:
Replace[lst, List[x__] -> foo[x], 1]
答案 4 :(得分:3)
Apply[]
上的答案是正确的,并且是正确的做法,但您要做的是用List[]
头代替Sequence[]
头部,即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]
。
因此foo@Delete[#,0]&/@{{a, b}, {c, d}, {e, f}}
会与foo@@@{{a, b}, {c, d}, {e, f}}
相同。
或者,foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}}
做同样的事情。