The function f references list as a free variable instead of as a parameter. While this is not an insurmountable obstacle, it does make it awkward to package up this functionality so that it can be used in a Table. Let's rework these definitions and apply some simplifications along the way.
First, let's tackle the test as to whether a sample is acceptable:
acceptableQ[sample_] :=
MemberQ[sample, n_ /; n > 31] &&
1 <= Count[sample, n_ /; n <= 12] <= 2 &&
Count[sample, n_ /; divisible2to7[n]] <= 3
divisible2to7[n_] := MemberQ[Range[2, 7], d_ /; Divisible[n, d]]
The main simplification from the original is that the nested If statements have been flattened into an And condition. The new definition also exploits the fact that Count can test list values without having to invoke a nested Select. In addition, existence checks have been expressed using MemberQ[...]. A helper function has been introduced to perform the divisibility check in an effort to reduce the visual complexity of the main test expression. Note that the original divisibility check was incorrectly returning a list where a boolean value was expected. The _Integer head tests were removed, but if they are deemed desirable they can be re-introduced by changing each n_ to n_Integer.
Now we just need a way to generate samples in a loop until an acceptable one is found:
generateSample[] :=
While[
True
, RandomSample[Range[36], 7] /.
s_ :> If[acceptableQ[s], Return[Sort @ s]]
]
generateSample[] can now be used to generate a table of as many results as needed:
In[113]:= Table[generateSample[], {5}]
Out[113]= {{6, 13, 17, 19, 25, 29, 33}, {1, 11, 13, 15, 31, 35, 36},
{1, 10, 17, 23, 25, 31, 32}, {1, 6, 17, 19, 22, 23, 33},
{8, 17, 19, 23, 30, 31, 36}}
Generalizing the Pattern
The pattern embodied in generateSample could be parameterized to accept arbitrary generator and filter functions:
SetAttributes[generatorSelect, HoldFirst]
generatorSelect[generator_, predicate_] :=
While[True, generator /. s_ :> If[predicate[s], Return[s]]]
The generator argument is kept in unevaluated form so that can be evaluated afresh on each pass through the loop. This new function can be used thus:
In[114]:= Table[
generatorSelect[RandomSample[Range[36], 7], acceptableQ] // Sort
, {5}
]
Out[114]= {{9, 17, 19, 23, 27, 29, 32}, {8, 13, 17, 19, 22, 23, 35},
{4, 17, 19, 21, 23, 29, 36}, {1, 8, 15, 19, 23, 31, 33},
{1, 10, 17, 19, 24, 29, 36}}
The advantage of the new function is that it can be used with any generator and filter functions. Here we generate tuples of three integers that sum to seven.
In[115]:= Table[
generatorSelect[RandomInteger[7, 3], Total[#] == 7 &]
, {5}
]
Out[115]= {{2, 3, 2}, {0, 5, 2}, {5, 0, 2}, {2, 4, 1}, {2, 1, 4}}
As a matter of style, some prefer to avoid defining functions with Hold attributes unless absolutely necessary. generatorSelect2 reflects that design choice:
generatorSelect2[generator_, predicate_] :=
While[True, generator[] /. s_ :> If[predicate[s], Return[s]]]
The only difference between this and generatorSelect is that the first argument is now expected to evaluate to a function:
In[116]:= Table[
generatorSelect2[RandomInteger[7, 3] &, Total[#] == 7 &]
, {5}
]
Out[116]= {{5, 1, 1}, {3, 0, 4}, {0, 1, 6}, {3, 2, 2}, {4, 1, 2}}
;after it. As the loop selects a list matching the condition you want, thefafter the loop will then return the selected list. - rcollyer