9
$\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$
  • $\begingroup$ No it doesn't it will give me the second list. $\endgroup$ – Mr. Pi Dec 31 '14 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 '14 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 '14 at 1:37
  • $\begingroup$ @bbgodfrey i want to partition the second like the first $\endgroup$ – Mr. Pi Dec 31 '14 at 1:38
  • $\begingroup$ @bbgodfrey not at all. In fact, I deleted my comment. $\endgroup$ – Oleksandr R. Dec 31 '14 at 2:07
8
$\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$
  • 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 '14 at 23:45
5
$\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$
3
$\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$
  • $\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 '14 at 10:03
  • $\begingroup$ Not at all, @MrWizard. Thank you. $\endgroup$ – bbgodfrey Dec 31 '14 at 14:07
2
$\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$
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$
1
$\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$

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.