5

New to Mathematica, I have a nested list containing many lists(A) of 16 lists(B) of 3 integers(C). I wish to put in each (Aj, Bi, C2) the result of (Aj, Bi-1, C2)+(Aj, Bi, C1). I could do it with a loop, or a spreadsheet, but is there a more elegant way to do this using functions like Accumulate? I simplified the data here:

 myList = 
    {{{a, b}, {c, d}, {e, f}}, 
    {{g, h}, {i, j}, {k, l}}, 
    {{m, n}, {o, p}, {q, r}}, 
    {{s, t}, {u, v}, {w, x}}}

A simple replacement test function before using values of other elements:

myF[x_] := x*2
ReplacePart[myList, {_, _, 2} -> xx]

Result:

{{{a, xx}, {c, xx}, {e, xx}}, 
{{g, xx}, {i, xx}, {k, xx}}, 
{{m, xx}, {o, xx}, {q, xx}},
{{s, xx}, {u, xx}, {w, xx}}}

I tried many expressions in the function without success.

ReplacePart[myList, {_, _, 2} -> myF[ ??? ]]

should result:

{{{a, 2b}, {c, 2d}, {e, 2f}}, 
{{g, 2h}, {i, 2j}, {k, 2l}}, 
{{m, 2n}, {o, 2p}, {q, 2r}}, 
{{s, 2t}, {u, 2v}, {w, 2x}}}

How could Accumulate give this?

{{{a, a}, {c, a+c}, {e, a+c+e}}, 
{{g, g}, {i, g+i}, {k, g+i+k}}, 
{{m, m}, {o, m+o}, {q, m+o+q}}, 
{{s, s}, {u, s+u}, {w, s+u+w}}}

Thanks!

makundo
  • 53
  • 4

3 Answers3

6

I believe this achieves your goal:

Join @@ Map[Transpose[{#, Accumulate@#}] &, Transpose /@ myList, {2}]

Transpose is a very helpful function. This also exploits the level argument for Map and Join just recombines.

There are many ways to do things in Mathematica. There will no doubt other approaches.

ubpdqn
  • 60,617
  • 3
  • 59
  • 148
  • 2
    This will be faster on packed arrays: Transpose[{#, Accumulate@#} &@First@Transpose[myList, {3, 2, 1}], {3, 2, 1}]. – Michael E2 Dec 06 '15 at 21:10
5

ReplacePart is not the natural choice to apply a function to the innermost matrix elements. Simple and straightforward is ReplaceAll:

myList /. {a_, b_} :> {a, myF @ b} // MatrixForm

enter image description here

With very large matrices ReplaceAll can get slow. In this case one can do an "inline" replacement. Since this permanently changes myList we do it with a copy:

copy = myList;

copy[[All, All, 2]] *= 2;

Thanks @MichaelE2 for this terse notation

copy

enter image description here

Accumulate with

Transpose /@ Transpose[{#, Accumulate /@ #}] &[myList[[All, All, 1]]] // MatrixForm

enter image description here

eldo
  • 67,911
  • 5
  • 60
  • 168
5
myList = {
  {{a, b}, {c, d}, {e, f}}, 
  {{g, h}, {i, j}, {k, l}}, 
  {{m, n}, {o, p}, {q, r}}, 
  {{s, t}, {u, v}, {w, x}}
 };

For the first, one could do

MapAt[2 # &, myList, {All, All, 2}]
(* {
  {{a, 2*b}, {c, 2*d}, {e, 2*f}}, 
  {{g, 2*h}, {i, 2*j}, {k, 2*l}}, 
  {{m, 2*n}, {o, 2*p}, {q, 2*r}}, 
  {{s, 2*t}, {u, 2*v}, {w, 2*x}}
 } *)

or with your

myF[x_] := x*2

do

MapAt[myF, myList, {All, All, 2}]

As for the second, here's another version that is basically equivalent to ubpdqn's, but slightly less verbose:

Thread@{#, Accumulate@#} &@#[[All, 1]] & /@ myList

Or, a trickier variant:

Thread@{#, Accumulate@#} & @@@ Thread /@ myList

Here's a version that uses ReplaceAll, with a dummy variable to update so that we don't have to Accumulate:

Map[
  Module[{var = 0}, # /. {a_, b_} :> (var = var + a; {a, var})] &
  , myList
 ]

However, ReplaceAll with this pattern will fail when the sub-list is two elements long. Instead, we use Replace, and make the code more concise:

Module[{var = 0}, 
  Replace[#, {a_, b_} :> {a, var = var + a}, 2]
 ] & /@ myList
march
  • 23,399
  • 2
  • 44
  • 100