在 Mathematica 中使用 MapAt 中的 All

发布于 2024-12-22 10:17:42 字数 631 浏览 2 评论 0原文

我经常有一个成对的列表,因为

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 样式规范而不是 Part 样式规范。正确的解决办法是什么?

为了澄清,

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

I often have a list of pairs, as

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

and I want to do something, for instance Rescale, to all of the second elements without touching the first elements. The neatest way I know is:

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

There must be a way to do this without so much Transposeing. My wish is for something like this to work:

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

But my understanding is that MapAt takes Position-style specifications instead of Part-style specifications. What's the proper solution?

To clarify,

I'm seeking a solution where I don't have to repeat myself, so lacking double Transpose or double [[All,2]], because I consider repetition a signal I'm not doing something the easiest way. However, if eliminating the repetition requires the introduction of intermediate variables or a named function or other additional complexity, maybe the transpose/untranspose solution is already correct.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

无妨# 2024-12-29 10:17:42

使用 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]

这是设计很一般。

Use Part:

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

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

data

Create a copy first if you need to. (data2 = data then data2[[All, 2]] etc.)


Amending my answer to keep up with ruebenko's, this can be made into a function also:

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

partReplace[data, Rescale, All, 2]

This is quite general is design.

月下伊人醉 2024-12-29 10:17:42

我参加聚会迟到了,我所描述的内容与@先生的内容几乎没有什么不同。巫师有,所以最好将此答案视为对其解决方案的补充。我的部分借口是,首先,下面的函数封装的东西有点不同,更接近 MapAt 本身的语法,其次,它更通用,并且可以选择与 Listable 一起使用 函数,第三,我正在重现过去的解决方案 Mathgroup 线程正是针对这个问题,该问题已有 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}}

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

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自动编译,请注意添加f 的 Listable 属性将完全被这里错误,会破坏目的,导致 mapAt 在这两种情况下都很慢。

I am coming late to the party, and what I will describe will differ very little with what @Mr. Wizard has, so it is best to consider this answer as a complementary to his solution. My partial excuses are that first, the function below packages things a bit differently and closer to the syntax of MapAt itself, second, it is a bit more general and has an option to use with Listable function, and third, I am reproducing my solution from the past Mathgroup thread for exactly this question, which is more than 2 years old, so I am not plagiarizing :)

So, here is the function:

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]; 

This is the same idea as what @Mr. Wizard used, with these differences: 1. In case when the spec is not of the prescribed form, regular MapAt will be used automatically 2. Not all functions are Listable. The solution of @Mr.Wizard assumes that either a function is Listable or we want to apply it to the entire list. In the above code, you can specify this by the MappedListable option.

I will also borrow a few examples from my answer in the above-mentioned thread:

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}}

Testing on large lists shows that using Listability improves the performance, although not so dramatically here:

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}

This is likely because for the above function (#/10&), Map (which is used internally in mapAt for the MappedListable->False (default) setting, was able to auto-compile. In the example below, the difference is more substantial:

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}

The point is that, while f was not declared Listable, we know that its body is built out of Listable functions, and thus it can be applied to the entire list - but OTOH it can not be auto-compiled by Map. Note that adding Listable attribute to f would have been completely wrong here and would destroy the purpose, leading to mapAt being slow in both cases.

归途 2024-12-29 10:17:42

哪个

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

会返回您想要的内容(即,它不会更改数据)?

如果不允许Transpose,则

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

可以工作。

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

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

80个字符,这与Mr.Wizard的相同......所以投票给他的回答

How about

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

which returns what you want (ie, it does not alter data)

If no Transpose is allowed,

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

works.

EDIT: As "shortest" is now the goal, best from me so far is:

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

at 80 characters, which is identical to Mr.Wizard's... So vote for his answer.

无畏 2024-12-29 10:17:42

这是另一种方法:

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]]]]

Here is another approach:

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

op[data, Rescale]

Edit 1:

An extension from Mr.Wizard, that does not copy it's data.

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

used like this

partReplace[data, Rescale, All, 2]

Edit 2:
Or like this

ReplacePart[data, {All, 2} -> Rescale[data[[All, 2]]]]
流心雨 2024-12-29 10:17:42

这对我和一个朋友有用

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}}

This worked for me and a friend

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}}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文