12
$\begingroup$

Hello I need some help on how to add a list to a list of list. The program would have to do as below:

{{0,0}, {0}, {0,0,0}}+{1,2,3,4,5,6} 

will give

{{1,2}, {3}, {4,5,6}}.

Could this be done? Any help is greatly appreciated. Thanks in advance.

$\endgroup$
6
  • $\begingroup$ No it doesn't it will give me the second list. $\endgroup$
    – Mr. Pi
    Dec 31, 2014 at 1:05
  • $\begingroup$ Welcome to Mathematica.SE! I suggest that: 1) You take the introductory Tour now! 2) When you see good questions and answers, vote them up by clicking the gray triangles, because the credibility of the system is based on the reputation gained by users sharing their knowledge. Also, please remember to accept the answer, if any, that solves your problem, by clicking the checkmark sign! 3) As you receive help, try to give it too, by answering questions in your area of expertise. $\endgroup$
    – bbgodfrey
    Dec 31, 2014 at 1:34
  • $\begingroup$ Do you wish to "add" the first list to the second or to partition the second list to have the structure of the first? It appears you mean the latter. Also, please explain your comment as it relates to the question. Thanks. $\endgroup$
    – bbgodfrey
    Dec 31, 2014 at 1:37
  • $\begingroup$ @bbgodfrey i want to partition the second like the first $\endgroup$
    – Mr. Pi
    Dec 31, 2014 at 1:38
  • $\begingroup$ @bbgodfrey not at all. In fact, I deleted my comment. $\endgroup$ Dec 31, 2014 at 2:07

8 Answers 8

11
$\begingroup$

Without testing whether there are as many elements in the first list as there are in the second, the solution is as simple as

listAdd[structured_, flat_] := Module[{i = 1},
  Function[elm, elm + flat[[i++]], {Listable}][structured]
]

listAdd[{{a, b}, {c}, {d, e, f}}, {1, 2, 3, 4, 5, 6}]
(* {{1 + a, 2 + b}, {3 + c}, {4 + d, 5 + e, 6 + f}} *)

To understand why this works, please study carefully my answer of this question.

$\endgroup$
1
  • 2
    $\begingroup$ This is elegant and flexible but it comes at the cost of performance: more than two orders of magnitude slower than add in the "Like/Long" test I just posted. $\endgroup$
    – Mr.Wizard
    Dec 31, 2014 at 23:45
6
$\begingroup$

Performance comparison

Here is a performance comparison of all methods given in the order of their posting.

Bill's code is not self-contained so I shall use:

bill[a_, b_] := 
 Module[{h, list = b}, 
  Map[(h = Take[list, Length[#]]; list = Drop[list, Length[#]]; # + h) &, a]
 ]

The other functions for ease of execution:

add[a_List, b_List] := a + dynP[b, Length /@ a]

listAdd[structured_, flat_] := 
 Module[{i = 1}, Function[elm, elm + flat[[i++]], {Listable}][structured]]

raggedMap = Internal`PartitionRagged[#1[Flatten[#2], #3], Length /@ #2] &;

listAdd1[structured_, flat_] := Module[{cnt = 1, f}, f = Function[x, x + flat[[cnt++]]];
  Map[f, structured, {-1}]]

deFlatten[flat_, reference_] := 
 Module[{cnt = 1}, Replace[reference, elem_ :> flat[[cnt++]], {-1}]]

listAdd2[structured_, flat_] := deFlatten[Flatten[structured] + flat, structured]

Yi Wang's listAdd3 threw errors so I did not include it in this test.

Generating code for two lists of the like type (Integer) with short sublists:

Needs["GeneralUtilities`"]

a = RandomInteger[9, #] & /@ RandomInteger[{1, 9}, 5000];
b = RandomInteger[9, Length@Flatten@a];

bill[a, b]             // AccurateTiming
add[a, b]              // AccurateTiming
listAdd[a, b]          // AccurateTiming
raggedMap[Plus, a, b]  // AccurateTiming
listAdd1[a, b]         // AccurateTiming
listAdd2[a, b]         // AccurateTiming

Like-types and long sublists:

a = RandomInteger[9, #] & /@ RandomInteger[{1, 500}, 500];
b = RandomInteger[9, Length@Flatten@a];

Unlike types and short sublists:

a = RandomInteger[9, #] & /@ RandomInteger[{1, 9}, 5000];
b = RandomChoice[{"a", "b", "c"}, Length@Flatten@a];

Unlike types and long sublists:

a = RandomInteger[9, #] & /@ RandomInteger[{1, 500}, 500];
b = RandomChoice[{"a", "b", "c"}, Length@Flatten@a];

A table of results:

enter image description here

$\endgroup$
0
4
$\begingroup$

This question is similar to 7511, which was solved with

dynP[l_, p_] := MapThread[l[[# ;; #2]] &, {{0}~Join~Most@# + 1, #} &@Accumulate@p]

In your case, dynP[{1, 2, 3, 4, 5, 6},{2, 1, 3}], where the second list is the lengths of the desired partitions, gives the answer. If, on the other hand, you wish to work from your template list, use

dynP[[{1, 2, 3, 4, 5, 6}, Length /@ {{0, 0}, {0}, {0, 0, 0}}]

As a function:

add[a_List, b_List] := a + dynP[b, Length /@ a]

Now:

add[{{2, 3}, {5}, {7, 11, 13}}, {1, 2, 3, 4, 5, 6}]
{{3, 5}, {8}, {11, 16, 19}}
$\endgroup$
2
  • $\begingroup$ Exactly how I would do it. +1 (And thanks for linking the source.) I added an example; I hope you don't mind. $\endgroup$
    – Mr.Wizard
    Dec 31, 2014 at 10:03
  • $\begingroup$ Not at all, @MrWizard. Thank you. $\endgroup$
    – bbgodfrey
    Dec 31, 2014 at 14:07
3
$\begingroup$

IF listoflist is only nested one level deep then

listoflist = {{0, 0}, {0}, {0, 0, 0}};
list = {1, 2, 3, 4, 5, 6};
Map[(h = Take[list, Length[#]]; list = Drop[list, Length[#]]; # + h) &, listoflist]

(* {{1, 2}, {3}, {4, 5, 6}} *)
$\endgroup$
0
3
$\begingroup$

Two ways to use Internal`CopyListStructure:

addLsts1 = # + Internal`CopyListStructure[#, #2] &;

addLsts1[{{a, b}, {c}, {d, e, f}}, Range@6]
 {{1 + a, 2 + b}, {3 + c}, {4 + d, 5 + e, 6 + f}}

addLsts1 is as fast as Mr.Wizard's add.

A slower alternative:

addLsts2 = Internal`CopyListStructure[#, Flatten[#] + #2] &;

addLsts2[{{a, b}, {c}, {d, e, f}}, Range@6]
{{1 + a, 2 + b}, {3 + c}, {4 + d, 5 + e, 6 + f}}
$\endgroup$
2
$\begingroup$
raggedMap = Internal`PartitionRagged[#1[Flatten[#2], #3], Length /@ #2] &;
raggedAdd = raggedMap[Plus, #, #2] &;

Usage examples:

raggedAdd {{0, 0}, {0}, {0, 0, 0}}, {1, 2, 3, 4, 5, 6}]

or

raggedMap[Plus, {{0, 0}, {0}, {0, 0, 0}}, {1, 2, 3, 4, 5, 6}]

both give

(* {{1, 2}, {3}, {4, 5, 6}} *)

lst1 = {{a, b}, {c}, {d, e, f}}; 
lst2 = {1, 2, 3, 4, 5, 6};
raggedAdd[lst1, lst2]
(* {{1+a, 2+b}, {3+c}, {4+d, 5+e, 6+f}} *)

raggedMap[Times, lst1, lst2]
(* {{a, 2 b}, {3 c}, {4 d, 5 e, 6 f}} *)
$\endgroup$
2
$\begingroup$

enter image description here

Using TakeList:

alist = {{a, b}, {c}, {d, e, f}};
blist = {1, 2, 3, 4, 5, 6};

alist + TakeList[blist, Length /@ alist]

{{1 + a, 2 + b}, {3 + c}, {4 + d, 5 + e, 6 + f}}

Also:

alist TakeList[blist, Length /@ alist]

{{a, 2 b}, {3 c}, {4 d, 5 e, 6 f}}

$\endgroup$
1
$\begingroup$

One solution: map at the last level

listAdd1[structured_,  flat_] := Module[{cnt = 1, f},
  f =  Function[x, x + flat[[cnt++]]];
  Map[f, structured, {-1}]]

Another solution: First define a function deFlatten[flat, reference], to undo Flatten, according to a given reference list:

deFlatten[flat_, reference_] := Module[{cnt = 1},
  Replace[reference, elem_ :> flat[[cnt++]], {-1}]]

For example,

deFlatten[{a, b, c}, {1, {2, 3}}]

{a, {b, c}}

Then it is trivial to implement listAdd:

listAdd2[structured_, flat_] := 
 deFlatten[Flatten[structured] + flat, structured ]

A third solution, by keeping the position of the list in MapIndexed, and restore the position using ReplacePart

listAdd3[structured_, flat_] := Module[{f}, ReplacePart[structured, 
  Flatten @ MapIndexed[f, structured, {-1}] + flat /. n_ + f[m_, pos_] :> (pos :> m + n)]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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