10

I have two lists which I would like to combine. One is of a random structure, which might be:

l1={{3, 2, 4, 2}, {2, 3}, {4, 3}, {{2, 2}}, {{3, 3}}, {3, 2}}

where the elements in each sublist may themselves be numbers, or lists.

From this, I create a list given by:

l2=Join[{0}, Accumulate[Flatten[l1, 1]]]

which gives in this case:

{0, 3, 5, 9, 11, 13, 16, 20, 23, {25, 25}, {28, 28}, {31, 31}, {33, 33}}

I now want to go through the original list, and append to each entry in that list, an entry from the second, in order, to end up with:

{{{3, 0}, {2, 3}, {4, 5}, {2, 9}}, {{2, 11}, {3, 13}}, {{4, 16}, {3, 20}}, {{{2, 2}, 23}}, {{{3, 3}, {25, 25}}}, {{3, {28, 28}}, {2, {31, 31}}}}

I can do this using a loop, but I would like to find a functional way to write it. I have tried using various map, list and thread commands, but so far have been unable to solve it.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Jonathan Shock
  • 3,015
  • 15
  • 24

4 Answers4

8

This matches your output:

Module[{i = 1},
  Map[{#, l2[[i++]]} &, l1, {2}]
]

If you don't need l2 separately you can eliminate the use of Accumulate entirely with:

Module[{t = 0},
  Map[{#, # &[t, t += #]} &, l1, {2}]
]

The inner function # &[t, t += #] is just a way to AddTo t but return the old value of t. Equivalently: First[{t, t += #}].

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
6

Also,

l3 = Internal`PartitionRagged[Most@l2, Length /@ l1];
Transpose /@ Transpose[{l1, l3}]

{{{3, 0}, {2, 3}, {4, 5}, {2, 9}},
{{2, 11}, {3, 13}},
{{4, 16}, {3, 20}},
{{{2, 2}, 23}},
{{{3, 3}, {25, 25}}},
{{3, {28, 28}}, {2, {31, 31}}}}

kglr
  • 394,356
  • 18
  • 477
  • 896
2

enter image description here

Using TakeList:

l1 = {{3, 2, 4, 2}, {2, 3}, {4, 3}, {{2, 2}}, {{3, 3}}, {3, 2}};
l2 = Join[{0}, Accumulate[Flatten[l1, 1]]];

Thread[{l1, TakeList[l2, Length /@ l1]}] // Map[Transpose]

{{{3, 0}, {2, 3}, {4, 5}, {2, 9}}, {{2, 11}, {3, 13}}, {{4, 16}, {3,
20}}, {{{2, 2}, 23}}, {{{3, 3}, {25, 25}}}, {{3, {28, 28}}, {2, {31, 31}}}}

Syed
  • 52,495
  • 4
  • 30
  • 85
2

Using MapThread and FoldPairList, an equivalent form to the one proposed by @Syed is the following:

l1 = {{3, 2, 4, 2}, {2, 3}, {4, 3}, {{2, 2}}, {{3, 3}}, {3, 2}};
l2 = Join[{0}, Accumulate[Flatten[l1, 1]]];
l3 = Length /@ l1;

MapThread[Transpose@List[#1, #2] &, {l1, FoldPairList[TakeDrop, l2, l3]}]

{ {{3, 0}, {2, 3}, {4, 5}, {2, 9}}, {{2, 11}, {3, 13}}, {{4, 16}, {3, 20}}, {{{2, 2}, 23}},
{{{3, 3}, {25, 25}}, {{3, {28, 28}}, {2, {31, 31}}}} }

E. Chan-López
  • 23,117
  • 3
  • 21
  • 44
  • 1
    The FoldPairList technique is in the docs as an equivalent to TakeList. I still struggle with the use of FoldPairList though. – Syed Apr 06 '23 at 03:21
  • The same thing happens to me, that's why I always pay attention to the posts where there's manipulation of lists. – E. Chan-López Apr 06 '23 at 20:40