5
$\begingroup$

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!

$\endgroup$
  • $\begingroup$ The solutions are so concise and powerful! It's very exiting to discover in the same time Mathematica and Stackexchange. Thank you march, ubpdqn and eldo for your answers. $\endgroup$ – makundo Dec 6 '15 at 21:32
  • $\begingroup$ For the first one, after Mr Wizard here: myList.{{1, 0}, {0, 2}}. Very fast, I think. $\endgroup$ – user1066 Jul 12 '16 at 18:06
5
$\begingroup$
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
$\endgroup$
  • $\begingroup$ Completely new to me that one can combine MapAt with All. Very handy, +1 $\endgroup$ – eldo Dec 6 '15 at 21:12
6
$\begingroup$

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.

$\endgroup$
  • 2
    $\begingroup$ This will be faster on packed arrays: Transpose[{#, Accumulate@#} &@First@Transpose[myList, {3, 2, 1}], {3, 2, 1}]. $\endgroup$ – Michael E2 Dec 6 '15 at 21:10
5
$\begingroup$

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

$\endgroup$
  • 1
    $\begingroup$ I think copy[[All, All, 2]] *= 2 will be faster on longer, large packed arrays. (+1) $\endgroup$ – Michael E2 Dec 6 '15 at 20:57
  • $\begingroup$ Of course, thanks for this valuable advice - will update :) $\endgroup$ – eldo Dec 6 '15 at 21:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.