【问题标题】:Using All in MapAt in Mathematica在 Mathematica 的 MapAt 中使用 All
【发布时间】:2011-12-20 18:23:13
【问题描述】:

我经常有一个配对列表,如

data = {{0,0.0},{1,12.4},{2,14.6},{3,25.1}}

我想对所有第二个元素做一些事情,例如Rescale,而不触及第一个元素。我知道的最简洁的方法是:

Transpose[MapAt[Rescale, Transpose[data], 2]]

必须有一种方法可以做到这一点,而无需太多Transposeing。我希望这样的事情能够奏效:

MapAt[Rescale, data, {All, 2}]

但我的理解是MapAt 采用Position-style 规范而不是Part-style 规范。什么是正确的解决方案?

澄清一下,

我正在寻找一个我不必重复自己的解决方案,所以缺少双 Transpose 或双 [[All,2]],因为我认为重复是一个信号,我没有做某事最简单的方法。但是,如果消除重复需要引入中间变量或命名函数或其他额外的复杂性,那么转置/非转置解决方案可能已经是正确的。

【问题讨论】:

  • 请注意[[All,2]] 的字符数与Transpose 相同。到目前为止,解决方案很有趣,但我认为没有一个比双转置更短,特别是如果您允许使用 esc-tr-esc 快捷方式。也许我应该把这个问题作为一个代码高尔夫挑战提出来?
  • 如果您想要一个更短的解决方案,您可能应该特别要求它。不同的人会认为不同的东西是(正确的或最优雅的或最容易理解的)解决方案。
  • 好吧,如果您根本不想要双倍Transpose 或双倍[[All,2]],我给出的两个答案似乎都很合适:)(不过,我会选择 Mr.W,它更容易阅读如果不写)
  • 为什么你是首先形成的数据,{{_Integer,_Real},..} 性能明智 {{__Integer},{__Real}} 哪里更好,然后你就不会有问题开始。
  • 谢谢大家的回答。做这些事情并不总是一种超级紧凑的方式。这些解决方案展示了在紧凑性和多功能性之间寻求平衡时可能的多样性。

标签: wolfram-mathematica


【解决方案1】:

使用Part:

data = {{0, 0.0}, {1, 12.4}, {2, 14.6}, {3, 25.1}}

data[[All, 2]] = Rescale @ data[[All, 2]];

data

如果需要,请先创建一个副本。 (data2 = data 然后data2[[All, 2]] 等等)


修改我的答案以跟上 ruebenko 的,这也可以变成一个函数:

partReplace[dat_, func_, spec__] :=
  Module[{a = dat},
    a[[spec]] = func @ a[[spec]];
    a
  ]

partReplace[data, Rescale, All, 2]

这是很笼统的设计。

【讨论】:

  • 用你自己的话来说,+1 表示完全按照我的方式去做(但请参阅下面的回答,了解一些细微的差异)
【解决方案2】:

我迟到了,我将描述的内容与@Mr. 的内容几乎没有什么不同。向导有,因此最好将此答案视为对他的解决方案的补充。我的部分借口是,首先,下面的函数封装的东西有点不同,更接近 MapAt 本身的语法,其次,它更通用,并且可以选择与 Listable 函数一起使用,第三,我我正在从过去的Mathgroup thread 复制我的解决方案,正是这个问题,这个问题已经超过 2 年了,所以我没有抄袭:)

所以,函数如下:

ClearAll[mapAt,MappedListable]; 
Protect[MappedListable]; 
Options[mapAt] = {MappedListable -> False}; 
mapAt[f_, expr_, {pseq : (All | _Integer) ..}, OptionsPattern[]] := 
  Module[{copy = expr}, 
    copy[[pseq]] = 
      If[TrueQ[OptionValue[MappedListable]] && Head[expr] === List, 
        f[copy[[pseq]]], 
        f /@ copy[[pseq]] 
      ]; 
    copy]; 
mapAt[f_, expr_, poslist_List] := MapAt[f, expr, poslist]; 

这与@Mr. 的想法相同。使用向导,有以下区别: 1. 如果规格不是规定的形式,将自动使用常规MapAt 2. 并非所有功能都是Listable。 @Mr.Wizard 的解决方案假定函数是 Listable 或者我们想将其应用于整个列表。在上面的代码中,你可以通过MappedListable选项来指定。

我也会从我在上述帖子中的回答中借用几个例子:

In[18]:= mat=ConstantArray[1,{5,3}];

In[19]:= mapAt[#/10&,mat,{All,3}]
Out[19]= {{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10},{1,1,1/10}}

In[20]:= mapAt[#/10&,mat,{3,All}]
Out[20]= {{1,1,1},{1,1,1},{1/10,1/10,1/10},{1,1,1},{1,1,1}}

在大型列表上进行的测试表明,使用 Listability 可以提高性能,尽管这里并没有那么显着:

In[28]:= largemat=ConstantArray[1,{150000,15}];

In[29]:= mapAt[#/10&,largemat,{All,3}];//Timing
Out[29]= {0.203,Null}

In[30]:= mapAt[#/10&,largemat,{All,3},MappedListable->True];//Timing
Out[30]= {0.094,Null}

这可能是因为对于上述函数 (#/10&),Map(在 mapAt 内部用于 MappedListable->False(默认)设置)能够自动编译。在下面的示例中,差异更大:

ClearAll[f];
f[x_] := 2 x - 1;

In[54]:= mapAt[f,largemat,{All,3}];//Timing
Out[54]= {0.219,Null}

In[55]:= mapAt[f,largemat,{All,3},MappedListable->True];//Timing
Out[55]= {0.031,Null}

关键是,虽然f没有声明为 Listable我们知道它的主体是由 Listable 函数构建的,因此它可以应用于整个列表 - 但 OTOH 它不能由 Map 自动编译。请注意,将Listable 属性添加到f 在这里是完全错误的,并且会破坏目的,导致mapAt 在这两种情况下都很慢。

【讨论】:

  • 我怎么能不投票呢?您总是会带来更深入的分析。顺便说一句,“@Mr.Wizard 的解决方案假设一个函数是可列出的,或者我们想将它应用于整个列表。”根据示例,我认为这就是这个问题的重点。你的肯定是一个有趣的看法。您的最后一段强调了我之前想知道的一些事情:是否有,或者是否有某种方式来断言一个函数是“固有可列出的”?这可以帮助misuse case 4 here.
  • @Mr.Wizard 我认为可以实现类似 Listability 的类型推断来解决这个问题。这听起来甚至不是一个非常困难的问题。
  • 你有什么想法?目前对我来说这是一个非常松散的想法。
  • @Mr.Wizard 问题可以表述如下:给定一段代表函数调用的代码,确定结果是否将由适当的@内部并行化987654344@ 在评估这段代码期间调用的内核函数。但是我开始发现这并不是我最初想的那么简单的问题,所以我撤回了我之前的说法。
【解决方案3】:

怎么样

Transpose[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]

返回你想要的(即它不会改变data

如果不允许Transpose

Thread[Join[{#[[All, 1]], Rescale[#[[All, 2]]]} &@data]]

有效。

编辑:由于“最短”是现在的目标,到目前为止我最好的是:

data\[LeftDoubleBracket]All, 2\[RightDoubleBracket] = Rescale[data[[All, 2]]]

80 个字符,与 Mr.Wizard 的相同...所以投票给his answer

【讨论】:

  • 那比他现在用的还干净吗?
  • @Mr.W 好吧,显然我认为是(它使用索引而不是MapAt,转置和索引来定位要操作的元素,你不觉得这更干净吗? ),但当然不同的人有不同的想法。
  • 对不起,我不是故意粗鲁的。我想我关注的是 OP 的要求,即“在没有太多 Transposeing 的情况下做到这一点。”
  • @Mr.W 没有感觉到粗鲁。我同意你的看起来更干净;少了@,这很奇怪:)
【解决方案4】:

这是另一种方法:

op[data_List, fun_] := 
 Join[data[[All, {1}]], fun[data[[All, {2}]]], 2]

op[data, Rescale]

编辑 1

Mr.Wizard 的扩展,不会复制它的数据。

SetAttributes[partReplace, HoldFirst]
partReplace[dat_, func_, spec__] := dat[[spec]] = func[dat[[spec]]];

这样使用

partReplace[data, Rescale, All, 2]

编辑 2: 或者像这样

ReplacePart[data, {All, 2} -> Rescale[data[[All, 2]]]]

【讨论】:

  • ReplacePart 是我首先想到的,但我使用了{_, 2},但它失败了。编辑:哦,该死的,它仍然不起作用。 :-(( 这是 v8 的变化吗?
  • 这适用于 801 和 804。我手头没有 V7。这可能是固定的,但我不知道。
【解决方案5】:

这对我和一个朋友有用

In[128]:= m = {{x, sss, x}, {y, sss, y}}
Out[128]= {{2, sss, 2}, {y, sss, y}}

In[129]:= function[ins1_] := ToUpperCase[ins1];
fatmap[ins2_] := MapAt[function, ins2, 2];

In[131]:= Map[fatmap, m]
Out[131]= {{2, ToUpperCase[sss], 2}, {y, ToUpperCase[sss], y}}

【讨论】:

    猜你喜欢
    • 2023-01-13
    • 2012-01-11
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 2011-09-22
    • 2011-05-06
    相关资源
    最近更新 更多