7

I have this:

list[1]={1,2,3};
list[2]={7,8,9};
list[3]={15,20,22};

I want this:

cumulativeList[1]={1,2,3};
cumulativeList[2]={1,2,3,7,8,9};
cumulativeList[3]={1,2,3,7,8,9,15,20,22};

Sort of like Accumulate, but using Join instead of Sum. I think it might be possible using FoldList but I'm getting confused.

Toph
  • 179
  • 4
  • Well, then why don't you try to use FoldList with Join for this? It will work! :) – Theo Tiger Jul 01 '13 at 10:28
  • You shouldn't use capital letters in the beginning of variable names, if that's what List is. It will cause collisions, as in this case. – C. E. Jul 01 '13 at 10:32
  • I tried Theo but must've done something wrong. And oops Anon, I changed it in the question so folks don't get unnecessarily confused... thanks! – Toph Jul 01 '13 at 10:56
  • 1
    Toph, your idea is absolutely right. You need Accumulate with Join instead of Sum. And you can use FoldList. So have a look at the documentation for Accumulate, it says: Accumulate[list] is effectively equivalent to Rest[FoldList[Plus,0,list]]. So there you go! Try Rest[FoldList[Join,{},list]]. – Theo Tiger Jul 01 '13 at 11:40
  • One question: will list and cumulativeList be regular Lists? So, is list actually list = {{1,2,3},{7,8,9},{15,20,22}} or is list just a Symbol (as suggested by the code you have pasted)? If you are unsure, let me suggest that {{1,2,3},{7,8,9},{15,20,22}} is what you want. – Theo Tiger Jul 01 '13 at 12:33
  • 1
    Ok, let me rewrite that question: are you aware of the fact that you are not constructing a List by doing list[1]=... but merely assigning values to a symbol? [] associates values to symbols. In contrast, [[]] refers to list indices. In the title you wrote that you have a list of lists, and that would be list={{1,2,3}..} as mentioned in the comment above. Since the answers so far do not deal with list actually being a List, this is a question to think about first. – Theo Tiger Jul 01 '13 at 12:47
  • Maybe it is not clear to the OP that doing list[1] = {1, 2, 3};list[2] = {7, 8, 9};list[3] = {15, 20, 22}; is not the same as doing list={{1,2,3},{7,8,9},{15,20,22}} ? – andre314 Jul 01 '13 at 13:56
  • 1
    Wow just checked back and I'm floored and delighted with the amount of activity here. Theo and Andre, you're correct that I hadn't understood that. Y'all are great, I have to go but I'll look over all of this, thanks for the help, I'll be back. – Toph Jul 02 '13 at 09:24

11 Answers11

14

Rather than using FoldList, this seems to be a perfect application of recursion and memoization, which leads to a very elegant solution:

(* Your original list *)
list[1] = {1, 2, 3};
list[2] = {7, 8, 9};
list[3] = {15, 20, 22};

(* The cumulative list *)
cumulativeList[0] = {};
cumulativeList[n_] := cumulativeList[n] = cumulativeList[n - 1] ~Join~ list[n]

Now you just need to evaluate cumulativeList[3] and automatically, all the other values (i.e. 1, 2) are calculated.

cumulativeList[3]
(* {1, 2, 3, 7, 8, 9, 15, 20, 22} *)

Table[cumulativeList[n], {n, 3}]
(* {{1, 2, 3}, {1, 2, 3, 7, 8, 9}, {1, 2, 3, 7, 8, 9, 15, 20, 22}} *)
rm -rf
  • 88,781
  • 21
  • 293
  • 472
  • hmm, although I like the concept of memoization, I think this is not a good example of it. FoldList is specifically made for this purpose and it will not re-evaluate. Also, intuitively, I would not do this with recursive code, but this might be something personal, as I tend to use recursive programming in Mathematica only on very rare occasions (same for iterative programming). Moreover, I believe memoization would require variable localization and it produces memory overhead, so in summary I don't feel this is as clean a code as with FoldList. – Theo Tiger Jul 01 '13 at 12:06
  • @TheoTiger What do you mean this will "re-evaluate"? The explicit purpose of memoization is to compute once and store the result, so as to avoid re-evaluation, so I'm not sure why you think this does. Also, what do you mean "variable localization" and "memory overhead"? This is the exact structure that the OP specifically asked for in the question, with the addition of down-values for 0 and n_ (which can be removed after computing, if it bothers you). – rm -rf Jul 01 '13 at 12:15
  • FoldList will also avoid re-evaluation of previous terms, as does memoization. Yep, you either need to clean up after computation or use something like Module[{comulativeList},...] in order to re-use this function for a different list and to release memory consumed by the down-values. However, I somehow feel this is too complicated for this rather straight-forward problem, what do you think? – Theo Tiger Jul 01 '13 at 12:27
  • You are right, your version exactly matches the structures being asked for. However, rather than fulfilling that specific structure, I would take a wild guess and say to the questioner that list and cumulativeList being regular Lists is more likely to be what he wants. This is why I interpreted his question like that in first place, but I will ask him. – Theo Tiger Jul 01 '13 at 12:29
  • This is nice, +1. For very large list of lists, you may want to memoize the partial linked lists instead, and then Flatten them and use a single Join when the function is later called for a particular n. This would make the initial call very fast (linear in the number of lists), for the price of some (not very significant) added overhead for the subsequent calls for specific n. As of now, your initial call is O(m^2), where m is the total number of elements in all lists. – Leonid Shifrin Jul 01 '13 at 19:07
5
list[1] = {1, 2, 3};
list[2] = {7, 8, 9};
list[3] = {15, 20, 22};

With[{x = Array[cumulativelist, 3]}, 
 x = Rest@FoldList[Join, {}, Array[list, 3]]]

{{1, 2, 3}, {1, 2, 3, 7, 8, 9}, {1, 2, 3, 7, 8, 9, 15, 20, 22}}

cumulativelist[3]

{1, 2, 3, 7, 8, 9, 15, 20, 22}

Chris Degnen
  • 30,927
  • 2
  • 54
  • 108
4

Here is a solution :

list[1] = {1, 2, 3};
list[2] = {7, 8, 9};
list[3] = {15, 20, 22};

Fold[Join[#1, #2] &, {}, {list[1]}]
Fold[Join[#1, #2] &, {}, {list[1], list[2]}]
Fold[Join[#1, #2] &, {}, {list[1], list[2], list[3]}]

{1, 2, 3}
{1, 2, 3, 7, 8, 9}
{1, 2, 3, 7, 8, 9, 15, 20, 22}

Note that the variable list begins with a lowercase. Using a uppercase is not recommended. It enters in conflict with Mathematica symbol names.

andre314
  • 18,474
  • 1
  • 36
  • 69
  • 1
    You could just use Join instead of Join[#1, #2] &. And using FoldList as in Rest[FoldList[Join, {}, {list[1], list[2], list[3]}]] might simplify things further – Pinguin Dirk Jul 01 '13 at 10:46
  • OK thanks! I ended up doing this: Do[cumulativeList[i] = Flatten[Drop[list, {i + 1, 20}]],{i, 20}]; i.e. flattening progressively less-truncated subsets of the original list of lists. Worked for me & appears to have the advantage of scaling to any number of lists (here 20) without making you type list[1],list[2],list[3]... does that make sense? – Toph Jul 01 '13 at 11:03
  • It would have sense only if list = {{1,2,3},{7,8,9},{15,20,22}}, which is not the case with the definitions : list[1]={1,2,3};list[2]= ... . I can't understand that you say "Worked for me". If you want to see what is really list, type ?list then shift-return. – andre314 Jul 01 '13 at 14:19
4

Table offers a simple approach without recursion and memoization.

concatenate[f_, {n_, m_}] := Join @@ Table[f[k], {k, n, m}]

Example

concatenate[list, {1, 3}]

{1, 2, 3, 7, 8, 9, 15, 20, 22}

DavidC
  • 16,724
  • 1
  • 42
  • 94
3

Perhaps even simpler is to use Map

list[1] = {1, 2, 3};
list[2] = {7, 8, 9};
list[3] = {15, 20, 22}; 
Flatten[list[#] & /@ Range[3]]

{1, 2, 3, 7, 8, 9, 15, 20, 22}

You can make this into a function easily

cumList[list_] := Flatten[list[#] & /@ Range[Length[DownValues[list]]]]

Calling cumList[list] then gives the same answer as above. (Thanks to Anon for noticing the extra Join).

bill s
  • 68,936
  • 4
  • 101
  • 191
3

Perhaps the shortest solution is this:

Flatten@DownValues[list][[All, 2]]

{1, 2, 3, 7, 8, 9, 15, 20, 22}

And the requested function cumulativeList:

cumulativeList[n_] := Flatten@DownValues[list][[1 ;; n, 2]]

In case you chose to write your list like this instead, it would be simpler:

list = {{1, 2, 3}, {7, 8, 9}, {15, 20, 22}}

Namely,

cumulativeList[n_] := Flatten[list[[1 ;; n]]]
C. E.
  • 70,533
  • 6
  • 140
  • 264
1
Flatten[list /@ #] & /@ Range[Range[3]]

{{1, 2, 3}, {1, 2, 3, 7, 8, 9}, {1, 2, 3, 7, 8, 9, 15, 20, 22}}

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

Here is an iterative example:

(* Your lists *)
Clear[cumulativeList]
cumulativeList[n_] := Module[{},
  cumulativeList[0] = {};
  For[x = 0, x < n, x++,
   Print[cumulativeList[x + 1] = 
     Join[cumulativeList[x], list[x + 1]]]]]

 cumulativeList[1]

 (*{1, 2, 3}*)
 cumulativeList[2]

 (*{1, 2, 3, 7, 8, 9}*)
 cumulativeList[3]

 (*{1, 2, 3, 7, 8, 9, 15, 20, 22}*)
Clif
  • 697
  • 4
  • 12
1
FoldList[(cumulativeList[#2[[1, 1, 1]]] = Join[#1, #2[[2]]]) &, {}, 
 DownValues[list]]

This gives you all the indexed variables at once (which is what you asked), rather than providing a function to calculate them. Works for all available indices, even with gaps in numbering and even for non-numeric indices.

panda-34
  • 1,268
  • 7
  • 8
1

Here's a one-liner using Join and a pure function:

list[1] = {1, 2, 3};
list[2] = {7, 8, 9};
list[3] = {15, 20, 22};

JoinList[number_] := Join @@ (list[#] & /@ Range[number]);

Then you can evaluate

JoinList[1]

{1, 2, 3}

JoinList[2]

{1, 2, 3, 7, 8, 9}

JoinList[3]

{1, 2, 3, 7, 8, 9, 15, 20, 22}

Hope this helps!

cartonn
  • 1,005
  • 6
  • 15
0

Terse syntax for FoldList:

FoldList[Join, Array[list, 3]]
{{1, 2, 3}, {1, 2, 3, 7, 8, 9}, {1, 2, 3, 7, 8, 9, 15, 20, 22}}

Reference:

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