7
$\begingroup$

Given an integer, say 20, how can I create the following irregular list of lists?

lst={5,7,3,5};
Range[#]&/@lst;

generates this:

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

I like to have the following list of lists:

{{1,2,3,4,5}, {6,7,8,9,10,11,12}, {13,14,15}, {16,17,18,19,20}}

If the list of lists was a regular sequence, I could use:

Partition[Range[20], 5]] 
$\endgroup$
4
  • 7
    $\begingroup$ TakeList[Range@ Total@(a = {5, 7, 3, 5}), a] $\endgroup$
    – Rabbit
    Apr 20, 2022 at 1:27
  • 2
    $\begingroup$ Or TakeList[Range@Total@#,#]&@lst $\endgroup$
    – user1066
    Apr 20, 2022 at 7:37
  • 3
    $\begingroup$ Range[#]&/@lst; could be Range/@lst; $\endgroup$ Apr 20, 2022 at 10:09
  • 2
    $\begingroup$ @AsukaMinato Or Range@lst! $\endgroup$
    – user1066
    Apr 20, 2022 at 10:28

7 Answers 7

11
$\begingroup$
lst = {5, 7, 3, 5};
  1. First way:

We have

Internal`PartitionRagged[Range@20, lst]
  1. Another one

We have

TakeList[Range@20, lst]

The output is:

list

$\endgroup$
13
$\begingroup$

This is the classic use-case for FoldPairList:

FoldPairList[TakeDrop, Range[20], {5, 7, 3, 5}]

Alternatively, I recently made a resource function for the situation where you want to split at specific positions:

ResourceFunction["SplitAtPositions"][Range[20], {5, 12, 15}, After]
$\endgroup$
1
  • 1
    $\begingroup$ Congrats on the SplitAtPositions. I will keep that in mind :-) $\endgroup$
    – bmf
    Apr 19, 2022 at 21:30
6
$\begingroup$

Although TakeList is the built-in function to do this, but if you want to do it randomly then a bit of setup would be helpful:

n = 20; (* list length *)
k = 5; (* # parts of list *)
alist = Range[n]
parts = IntegerPartitions[n, {k}]
SeedRandom[1];
TakeList[alist, RandomChoice[parts]]
{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14}, {15, 16, 17, 
  18}, {19, 20}}
$\endgroup$
6
$\begingroup$

Sightly long.

lst={5,7,3,5};
len = Total@lst;
index = Accumulate[lst];
diff = Join[{{1,lst[[1]]}}, Transpose[{index[[;;-2]]+1, index[[2;;]]}]];
(Range@len)[[#1;;#2]]&@@@diff
$\endgroup$
5
$\begingroup$

Starting from your two lines:

lst = {5, 7, 3, 5};
ints = Range[#] & /@ lst;

ints + Flatten[{0, Drop[Accumulate[lst], -1]}]
{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11, 12}, {13, 14, 15}, {16, 17, 18, 19, 20}}
$\endgroup$
5
$\begingroup$

We create a RangePartition function:

RangePartition[list_List] := MapAt[{#[[1]] + 1, #[[2]]} &, Partition[Flatten[Append[{1}, Accumulate[list]]], 2, 1], Outer[List, Range[2, Length[list]]]]

Also, we create a RangeList function:

RangeList[list_List] := Block[{arraysymb, symb, rangesymb,rangelist},
arraysymb = Array[Subscript[symb, ##] &, 2, 1];
rangesymb = Array[Subscript[symb, ##] &, 2, 1, HoldForm[Range]];
rangelist = 
ReleaseHold[ReplaceAll[Thread[arraysymb -> list]][rangesymb]];
Return[rangelist]]

Then:

Map[RangeList, RangePartition[lst]]

(*{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11, 12}, {13, 14, 15}, {16, 17, 18,19, 20}}*)
$\endgroup$
3
$\begingroup$

Further alternatives:

ClearAll[f, g, h]

f = FoldList[#2 + Last @ # &] @* Range;

g = Range @ # + Prepend[0] @ Most @ Accumulate @ # &;

h = Total @* Through @* {Range, Prepend[0] @* Most @* Accumulate}

Examples:

f @ lst
{{1, 2, 3, 4, 5}, {6, 7, 8, 9, 10, 11, 12}, {13, 14, 15}, {16, 17, 18, 19, 20}}
f @ lst == g @ lst == h @ lst
True
$\endgroup$
1
  • 1
    $\begingroup$ so happy to have seen this answer for two reasons. 1. we did the tenfold way AGAIN and 2. well...it's an answer by you. Do I need more than that? Nicely done!!! $\endgroup$
    – bmf
    Apr 22, 2022 at 14:10

Your Answer

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

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