Convert list of lists to cumulative join

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.

-
Well, then why don't you try to use FoldList with Join for this? It will work! :) –  Theo Tiger Jul 1 '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. –  Pickett Jul 1 '13 at 10:32
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 1 '13 at 11:40
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 1 '13 at 12:47
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 2 '13 at 9:24

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}} *)

-
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 1 '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). –  The Toad Jul 1 '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 1 '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 1 '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 1 '13 at 19:07

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.

-
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 1 '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 1 '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. –  andre Jul 1 '13 at 14:19

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}

-
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}

-

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).

-
I believe Join is superfluous: Flatten[list[#] & /@ Range[Length[DownValues[list]]]] –  Pickett Jul 1 '13 at 13:09

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]]]

-

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}*)

-
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.

-

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!

-
This isn't fundamentally different from bill s' or David's answer. –  The Toad Jul 1 '13 at 21:48
@rm-rf Yup, looks almost exactly the same, I only realized it after I posted.. –  cartonn Jul 1 '13 at 21:51