将函数映射到列表时如何删除额外的 {}
简单的问题,给定一个这样的列表
Clear[a, b, c, d, e, f];
lst = {{a, b}, {c, d}, {e, f}};
,假设我有一个像这样定义的函数:
foo[x_,y_]:=Module[{},...]
并且我想将此函数应用于列表,所以如果我输入
Map[foo, lst]
This 给出
{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]}
(更少的打字,但需要先转置)
问题:还有其他更好的方法吗?执行上述操作?我查看了其他 Map 及其朋友,但我看不到比我拥有的功能更直接的功能。
Simple question, given a list like this
Clear[a, b, c, d, e, f];
lst = {{a, b}, {c, d}, {e, f}};
and suppose I have a function defined like this:
foo[x_,y_]:=Module[{},...]
And I want to apply this function to the list, so If I type
Map[foo, lst]
This gives
{foo[{a, b}], foo[{c, d}], foo[{e, f}]}
I want it to come out as
{foo[a, b], foo[c, d], foo[e, f]}
so it works.
What is the best way to do this? Assume I can't modify the function foo[] definition (say it is build-in)
Only 2 ways I know now are
Map[foo[#[[1]], #[[2]]] &, lst]
{foo[a, b], foo[c, d], foo[e, f]}
(too much work), or
MapThread[foo, Transpose[lst]]
{foo[a, b], foo[c, d], foo[e, f]}
(less typing, but need to transpose first)
Question: Any other better ways to do the above? I looked at other Map and its friends, and I could not see a function to do it more directly than what I have.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您需要在
Level
1 处进行Apply
或其缩写形式@@@
You need
Apply
atLevel
1 or its short form,@@@
一种可能的方法是将
lst
的每个元素的 head 从List
更改为foo
:One possible way is to change head of each element of
lst
fromList
tofoo
:只是报告这两种方法(
@@@
、@@ # & /@
)令人费解的性能测试:这些结果不是随机的,而是对于非常不同的结果大致成比例数据大小。
@@@
对于Subtract
、Divide
、Power
、Log< 的速度大约快 3-4 倍/code> while
@@ # & /@
的速度比Plus
和Times
快 4 倍,从而引发了另一个问题,(正如人们所相信的那样)可能会稍微通过以下评估澄清:
只有
Plus
和Times
具有属性Flat
和Orderless
,而其余的只有 < code>Power(这似乎是相对最有效的)还有一个属性OneIdentity
。编辑
对观察到的性能提升的可靠解释(感谢 Leonid Shifrin 的评论)应该走不同的路线。
默认情况下有
MapCompileLength -> 100
,因为我们可以检查评估SystemOptions["CompileOptions"]
。要重置 Map 的自动编译,我们可以评估:
现在我们可以通过再次评估相关符号和列表的
H
性能测试函数来测试这两种方法的相对性能:有了这些结果,我们可以得出结论:一般 Yoda 的方法 (
@@@
) 是最有效的,而 Andrei 提供的方法在Plus
和Times
的情况下更好,因为自动Map
的编译允许(@@ # & /@
) 的性能更好。Just to report puzzling performance tests of the both methods (
@@@
,@@ # & /@
) :These results are not random, but roughly proportional for very different data sizes.
@@@
is roughly 3-4 times faster forSubtract
,Divide
,Power
,Log
while@@ # & /@
is 4 times faster forPlus
andTimes
giving rise to another questions, which (as one can believe) could be slightlyclarified by the following evaluation:
Only
Plus
andTimes
have attributesFlat
andOrderless
, while among the rest onlyPower
(which seems relatively the most efficient there) has also an attributeOneIdentity
.Edit
A reliable explanation to observed performance boosts (thanks to Leonid Shifrin's remarks) should go along a different route.
By default there is
MapCompileLength -> 100
as we can check evaluatingSystemOptions["CompileOptions"]
.To reset autocompilation of Map we can evaluate :
Now we can test relative performance of the both methods by evaluating once more our
H
- performance testing function on related symbols and list :Having these result we can conclude that in general Yoda's approach (
@@@
) is the most efficient, while that provided by Andrei is better in case ofPlus
andTimes
due to automatic compilation ofMap
allowing better performance of (@@ # & /@
).还有一些可供选择的可能性:
这是尤达答案的更详细版本。它仅在列表
lst
的第 1 层应用foo
(将头List
替换为头foo
):其作用相同,但将
Apply
映射到列表lst
(本质上是 Andrei 的答案):这只是在级别 1 将模式 List[x__] 替换为 foo[x] :
A few more possibilities to pick from:
This one is a more verbose version of yoda's answer. It applies
foo
at level 1 of the listlst
only (replaces the headList
with the headfoo
):This does the same, but maps
Apply
over the listlst
(essentially Andrei's answer):And this just replaces the pattern List[x__] with foo[x] at level 1:
Apply[]
上的答案是正确的,并且是正确的做法,但是您想要做的是将List[]
头替换为Sequence[]
头,即List[List[3,5],List[6,7]]
应该变成List[Sequence[3,5],序列[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}}
执行相同的操作。The answers on
Apply[]
are spot on, and is the right thing to do, but what you were trying to do, was to replace aList[]
head with aSequence[]
head, i.e.List[List[3,5],List[6,7]]
should becomeList[Sequence[3,5],Sequence[6,7]]
.Sequence head is what naturally remains if a head of any list of parameters is deleted, so
Delete[Plus[3,5],0]
andDelete[{3,5},0]
andDelete[List[3,5],0]
would all produceSequence[3,5]
.So
foo@Delete[#,0]&/@{{a, b}, {c, d}, {e, f}}
will give you the same asfoo@@@{{a, b}, {c, d}, {e, f}}
.Alternatively,
foo[#/.List->Sequence]&/@{{a, b}, {c, d}, {e, f}}
does the same thing.