Mathematica:在Flatten之后重建一个任意嵌套列表

时间:2011-02-15 05:34:18

标签: wolfram-mathematica

将任意时髦的嵌套列表expr映射到函数unflatten的最简单方法是什么,以便expr==unflatten@@Flatten@expr

动机: Compile只能处理完整数组(我刚刚学到的东西 - 但不是错误信息),因此我的想法是将unflatten与扁平表达式的编译版本一起使用:

fPrivate=Compile[{x,y},Evaluate@Flatten@expr];
f[x_?NumericQ,y_?NumericQ]:=unflatten@@fPrivate[x,y] 

解决不太常见问题的示例: 我实际需要做的是计算给定多元函数的所有导数,直到某个顺序。对于这种情况,我这样修理:

expr=Table[D[x^2 y+y^3,{{x,y},k}],{k,0,2}];
unflatten=Module[{f,x,y,a,b,sslot,tt},
  tt=Table[D[f[x,y],{{x,y},k}],{k,0,2}] /. 
    {Derivative[a_,b_][_][__]-> x[a,b], f[__]-> x[0,0]};
  (Evaluate[tt/.MapIndexed[#1->sslot[#2[[1]]]&, 
            Flatten[tt]]/. sslot-> Slot]&) ] 

Out[1]= {x^2 y + y^3, {2 x y, x^2 + 3 y^2}, {{2 y, 2 x}, {2 x, 6 y}}}
Out[2]= {#1, {#2, #3}, {{#4, #5}, {#5, #7}}} &

这是有效的,但既不优雅也不一般。

编辑:以下是aaz提供的解决方案的“工作保障”版本:

makeUnflatten[expr_List]:=Module[{i=1},
    Function@Evaluate@ReplaceAll[
        If[ListQ[#1],Map[#0,#1],i++]&@expr,
        i_Integer-> Slot[i]]]

它很有魅力:

In[2]= makeUnflatten[expr]
Out[2]= {#1,{#2,#3},{{#4,#5},{#6,#7}}}&

3 个答案:

答案 0 :(得分:6)

您显然需要保存有关列表结构的一些信息,因为Flatten[{a,{b,c}}]==Flatten[{{a,b},c}]

如果ArrayQ[expr],则列表结构由Dimensions[expr]提供,您可以使用Partition重新构建它。 E.g。

expr = {{a, b, c}, {d, e, f}};
dimensions = Dimensions[expr]

  {2,3}

unflatten = Fold[Partition, #1, Reverse[Drop[dimensions, 1]]]&;
expr == unflatten @ Flatten[expr]

Partition手册页实际上有一个名为unflatten的类似示例。)


如果expr不是数组,您可以尝试:

expr = {a, {b, c}};
indexes = Module[{i=0}, If[ListQ[#1], Map[#0, #1], ++i]& @expr]

  {1, {2, 3}}

slots = indexes /. {i_Integer -> Slot[i]}

  {#1, {#2, #3}}

unflatten = Function[Release[slots]]

  {#1, {#2, #3}} &

expr == unflatten @@ Flatten[expr]

答案 1 :(得分:1)

我不确定你要用Compile做什么。当你想在数值上非常快速地评估程序或函数表达式时使用它,所以我认为它不会在这里有所帮助。如果重复计算D [f,...]会妨碍您的表现,您可以预先计算并存储类似的内容 Table[d[k]=D[f,{{x,y},k}],{k,0,kk}];

然后调用d [k]得到第k个导数。

答案 2 :(得分:1)

我只想更新aaz和Janus的优秀解决方案。看来,至少在Mac OSX上的Mathematica 9.0.1.0中,赋值(参见aaz的解决方案)

{i_Integer -> Slot[i]}

失败。但是,如果我们使用

{i_Integer :> Slot[i]}
相反,我们成功了。当然,同样适用于Janus的“工作保障”版本中的ReplaceAll电话。

为了更好的衡量,我包括我自己的功能。

unflatten[ex_List, exOriginal_List] := 
  Module[
   {indexes, slots, unflat},
   indexes = 
     Module[
       {i = 0}, 
       If[ListQ[#1], Map[#0, #1], ++i] &@exOriginal
       ];
   slots = indexes /. {i_Integer :> Slot[i]};
   unflat = Function[Release[slots]];
   unflat @@ ex
   ];

(* example *)
expr = {a, {b, c}};
expr // Flatten // unflatten[#, expr] &

在函数中使用原始表达式似乎有点像作弊,但正如aaz所指出的,我们需要来自原始表达式的一些信息。虽然你不需要它 all ,但为了拥有一个{em> single 函数,unflatten,一切都是必要的。

我的应用程序与Janus的类似:我正在调用Simplify来调用张量。使用ParallelTable我可以显着提高性能,但我破坏了过程中的张量结构。这为我提供了一种快速重建原始张量的方法,简化了。