# Split a sequence with conditions

I need a function which splits a sequence of arbitrary length

at x random points and which guarantees that each partition (bin) contains a minimum of y elements

RandomSplit[data_?VectorQ, x_Integer, y_Integer] := "?"


TakeList or SequenceSplit might be candidates to do this, but I don' t know how to get the partition lengths in a random manner and with the minimum binning size.

An example with 100 elements, 4 partitions and a minimum bin length of 10:

TakeList[Range[100], {10, 10, 70, 10}];


Or

TakeList[Range[100], {37, 21, 31, 10}];


But not

TakeList[Range[100], {5, 15, 50, 30}];

• Try: IntegerPartitions[100, {4}, Range[10, 100, 10]] and IntegerPartitions[100, {4}, Range[10, 100]] to see if these meet your needs. The second one has 1906 entries.
– Syed
Commented Sep 11, 2023 at 16:47
• RandomChoice[IntegerPartitions[100, {4}, Range[10, 100]]] is what I was looking for - please post this as an answer
– eldo
Commented Sep 11, 2023 at 16:56
• you probably need RandomSample@RandomChoice[IntegerPartitions[100, {4}, Range[10, 100]]]?
– kglr
Commented Sep 11, 2023 at 17:56
• Thank you, @kglr, that seems to work even better
– eldo
Commented Sep 11, 2023 at 18:02
• Will RandomChoice not give a single value? Why use the RandomSample as well? @eldo
– Syed
Commented Sep 12, 2023 at 8:15

The following will split the integer 100 into exactly four partitions, but with numbers restricted to multiples of 10.

IntegerPartitions[100, {4}, Range[10, 100, 10]]


{{70, 10, 10, 10}, {60, 20, 10, 10}, {50, 30, 10, 10}, {50, 20, 20,
10}, {40, 40, 10, 10}, {40, 30, 20, 10}, {40, 20, 20, 20}, {30, 30,
30, 10}, {30, 30, 20, 20}}

The following will partition the integer 100 into four partitions and selects results such that 37 appears in each set at least once.

IntegerPartitions[100, {4}, Range[20, 100]] //
Cases[#, {___, 37, ___}] &


{{37, 23, 20, 20}, {37, 22, 21, 20}, {37, 21, 21, 21}}

As another example the integer 100 can be divided using only the prime numbers:

primes = Table[Prime[i], {i, 1, PrimePi[100]}]


{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97}

IntegerPartitions[100, 2, primes]


{{97, 3}, {89, 11}, {83, 17}, {71, 29}, {59, 41}, {53, 47}}

• Thank you, @Syed, I've always regarded IntegerPartition as a number theory thing. Now I see that it can be useful in other contexts too.
– eldo
Commented Sep 12, 2023 at 8:11
• @eldo You are most welcome.
– Syed
Commented Sep 12, 2023 at 8:12

FrobeniusSolve

possibilities=Select[FrobeniusSolve[{1, 1, 1, 1}, 100],
#[[1]]>=10 && #[[2]]>=10 && #[[3]]>=10 && #[[4]]>=10&];

RandomChoice@possibilities

(* {39,22,13,26} *)


Table[RandomChoice@possibilities,10]

(*{
{42,10,29,19},
{18,24,48,10},
{17,37,17,29},
{30,21,31,18},
{17,14,43,26},
{11,25,25,39},
{41,19,24,16},
{14,18,15,53},
{37,22,19,22},
{25,19,12,44}
}*)

possibilities//Short

Length @possibilities

Length@FrobeniusSolve[{1, 1, 1, 1}, 100]

(*

{10,10,10,70},{10,10,11,69},<<39707>>,{69,11,10,10},{70,10,10,10}}

39711

176851

*)


Although this method is much less efficient that the IntegerPartitions method posted by @Syed, and may even come under the heading 'just for fun', it does provide a random sample with a minimum bin length of 10.

For an integer range between 10-100, there are 39711 four-element partitions where the total of each partition is 100.

(For a range 0-100, there are 176851 four-element partitions with a total of 100, and all of these are initially generated by the FrobeniusSolve method).

IntegerPartitions

As shown by @Syed:

(pList=IntegerPartitions[100,{4},Range[10,100]])//Short

(* {{70,10,10,10},{69,11,10,10},<<1902>>,{26,25,25,24},{25,25,25,25} *)


Length@pList

(* 1906 *)


However, the elements in each sublist produced by InterPartitions are ordered highest-to-lowest. {18,24,48,10}, for example, is not present.

MemberQ[pList, {18,24,48,10}]

(* False *)


As pointed out by @kglr in a comment, calling RandomSample on a RandomChoice from pList solves this problem.

RandomSample@RandomChoice@pList

(* {38,25,22,15} *)


As most, but not all, of the elements of pList (those of the form {a,b,c,d}) will produce 24 random samples, one would expect the total number of possibilities to be less than 1906x24 (45744). (I'm sure there is a way to mathematically calculate the value).

The FrobeniusSolve method produced a value of 39711 and the 'brute force' method can be used to check that calling RandomSample on the results of IntegerPartitions generates an identical number of possibilities:

Length@Union@((Table[RandomSample[#],
1000]&/@IntegerPartitions[100,{4},Range[10,100]])//Catenate)

(* 39711 *)

Union@((Table[RandomSample[#], 1000]&/@IntegerPartitions[100,{4},Range[10,100]])//Catenate)//Short

(* {{10,10,10,70},{10,10,11,69},<<39707>>,{69,11,10,10},{70,10,10,10}} *)