Nas*_*ser 7 wolfram-mathematica
我仍然不能很好地使用Mathematica中的列表来实现功能.这是一个小问题,我想问一下什么是一个很好的功能解决方法.
我说以下列表由点组成.因此,每个元素是一个点的坐标(x,y).
a = {{1, 2}, {3, 4}, {5, 6}}
Run Code Online (Sandbox Code Playgroud)
我想遍历这个列表,每当我找到一个y坐标为> 3.5的点时,我想生成一个复杂的共轭点.最后,我想返回生成的点列表.因此,在上面的例子中,有2个点可以满足这个条件.因此,最终列表中将有5个点,3个原始列表和2个复共轭点.
我试过这个:
If[#[[2]] > 3.5, {#, {#[[1]], -#[[2]]}}, #] & /@ a
Run Code Online (Sandbox Code Playgroud)
但我明白了
{{1, 2}, {{3, 4}, {3, -4}}, {{5, 6}, {5, -6}}}
Run Code Online (Sandbox Code Playgroud)
你会看到中间的额外{},我必须添加一个复共轭点.我希望结果是这样的:
{{1, 2}, {3, 4}, {3, -4}, {5, 6}, {5, -6}}
Run Code Online (Sandbox Code Playgroud)
我尝试插入Flatten,但没有工作,所以,我发现自己有时会回到我原来的程序方式,并使用像Table和Do这样的东西:
a = {{1, 2}, {3, 4}, {5, 6}}
result = {};
Do[
If[a[[i, 2]] > 3.5,
{
AppendTo[result, a[[i]]]; AppendTo[result, {a[[i, 1]], -a[[i, 2]]}]
},
AppendTo[result, a[[i]]]
],
{i, 1, Length[a]}
]
Run Code Online (Sandbox Code Playgroud)
这给了我想要的东西,但不是功能性解决方案,我不喜欢它.
什么是解决这种列表操作的最佳功能方法?
更新1
使用上面相同的数据,假设我想在遍历列表时对每个点进行计算,并使用此计算来构建列表.假设我想找到点的Norm(位置向量),并使用它来构建一个列表,其每个元素现在将是{norm,point}.并遵循与上述相同的逻辑.因此,唯一的区别是我在每一步都做了额外的计算.
这就是我使用提供的解决方案所做的事情:
a = {{1, 2}, {3, 4}, {5, 6}}
If[#[[2]] > 3.5,
Unevaluated@Sequence[ {Norm[#], #}, {Norm[#], {#[[1]], -#[[2]]}}],
{Norm[#], #}
] & /@ a
Run Code Online (Sandbox Code Playgroud)
这给了我想要的东西:
{ {Sqrt[5],{1,2}}, {5,{3,4}}, {5,{3,-4}}, {Sqrt[61],{5,6}}, {Sqrt[61],{5,-6}} }
Run Code Online (Sandbox Code Playgroud)
我对此唯一的问题是,我在3个地方重复了对Norm [#]的调用.如果没有这种重复计算,有没有办法做到这一点?
这就是我目前使用我的旧程序方式再次执行上述操作的方法:
a = {{1, 2}, {3, 4}, {5, 6}}
result = {};
Do[
o = Norm[a[[i]]];
If[a[[i, 2]] > 3.5,
{
AppendTo[result, {o, a[[i]]}]; AppendTo[result, {o, {a[[i, 1]], -a[[i, 2]]}}]
},
AppendTo[result, {o, a[[i]]}]
],
{i, 1, Length[a]}
]
Run Code Online (Sandbox Code Playgroud)
我得到了与功能方式相同的结果,但在上面,由于我使用了一个临时变量,我每个点进行一次计算.
这是播种和收获之类的地方吗?我真的从未理解这两个功能.如果没有,你会如何以功能的方式做到这一点?
谢谢
Sza*_*lcs 11
一种方法是使用Sequence
.
只需对您的解决方案进行微小修改:
If[#1[[2]] > 3.5, Unevaluated@Sequence[#1, {#1[[1]], -#1[[2]]}], #1] & /@ a
Run Code Online (Sandbox Code Playgroud)
但是,平原ReplaceAll
可能更简单:
a /. {x_, y_} /; y > 3.5 :> Sequence[{x, y}, {x, -y}]
Run Code Online (Sandbox Code Playgroud)
这种用法是确切的原因Rule
并RuleDelayed
具有属性SequenceHold
.
回答更新1
我分两步完成:
b = a /. {x_, y_} /; y > 3.5 :> Sequence[{x, y}, {x, -y}]
{Norm[#], #}& /@ b
Run Code Online (Sandbox Code Playgroud)
在实际的计算中,你有可能想要单独使用规范,所以Norm /@ b
可能会这样做
Mar*_*ure 10
Flatten
选择第二个参数,指定要展平的深度.因此,您还可以执行以下操作.
a = {{1, 2}, {3, 4}, {5, 6}};
Flatten[If[#[[2]] > 3.5, {#, {#[[1]], -#[[2]]}}, {#}] & /@ a, 1]
Run Code Online (Sandbox Code Playgroud)
你的Do
循环最严重的问题是使用AppendTo
.如果长得很result
长,这将非常缓慢.处理由于这样的过程而增长的列表的标准方法是使用Reap
和Sow
.在这个例子中,你可以这样做.
new = Reap[
Do[If[el[[2]] > 3.5, Sow[{el[[1]], -el[[2]]}]],
{el, a}]][[2, 1]];
Join[a, new]
Run Code Online (Sandbox Code Playgroud)
WRe*_*ach 10
虽然Mathematica可以很好地模拟函数式编程范例,但您可以考虑使用Mathematica的本机范例 - 模式匹配:
a = {{1,2},{3,4},{5,6}}
b = a /. p:{x_, y_ /; y > 3.5} :> Sequence[p, {x, -y}]
Run Code Online (Sandbox Code Playgroud)
然后,您可以进一步转换结果以包含Norm
s:
c = Cases[b, p_ :> {Norm@p, p}]
Run Code Online (Sandbox Code Playgroud)
毫无疑问,使用Sequence
生成非常大的列表并不像预先分配正确大小的数组那样高效,然后使用元素赋值更新它.然而,我通常更喜欢表达清晰度而非这种微优化,除非所测量的优化对我的应用至关重要.
要回答您的编辑,请使用With
(或Module
),如果您打算多次使用昂贵的东西.
这是我编辑中的问题版本:
a = {{1, 2}, {3, 4}, {5, 6}};
Table[With[{n = Norm[x]},
Unevaluated@Sequence[{n, x},
If[x[[2]] > 3.5, {n, {1, -1} x}, Unevaluated@Sequence[]]]],
{x, a}]
Run Code Online (Sandbox Code Playgroud)
可以修改上述结构以用于版本Map
或ReplaceAll
版本,但我认为Table
在这种情况下更清楚.没有评估的序列有点烦人.你也可以使用一些不确定的功能f
,然后替换f
用Sequence
在最后.