我曾在Mathematica中使用随机数生成器,并受到许多条件的抑制。现在我的代码看起来像这样:
list = RandomSample[Range[36], 7];
f := If[1 <= Count[Select[list, # <= 12 &], _Integer] <= 2,
If[Count[Select[list, # > 31 &], _Integer] >= 1,
If[Count[Select[list, Divisible[#, {2, 7}] &], _Integer] <= 3,
Sort[list], False], False], False]
While[f == False,
list = RandomSample[Range[36], 7];
If[list == f, f]];
f
它是这样构建的:
现在的事情是:这只产生一行输出。我有兴趣获得多个输出,例如5-10。我试图用Table命令以某种方式做到这一点,但问题是没有任何同时定义函数f和while循环。因此,通过在f上运行表格,我只会多次得到相同的结果。
有关如何进行此处的任何输入?
答案 0 :(得分:4)
我不认为f
定义中的第三行正在按照您的想法行事。考虑例如
Divisible[20, {2, 7}]
返回{True, False}
,而不是True
或False
。这意味着
Select[list, Divisible[#, {2, 7}] &]
将始终返回一个空列表
Count[Select[list, Divisible[#, {2, 7}] &], _Integer]
将始终返回0
。
如果我正确解释列表的条件,您可以使用类似
的内容Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3
有了这个和Alexy建议使用Sow
和Reap
,你可以做类似的事情
f[list_] := And[
1 <= Count[Select[list, # <= 12 &], _Integer] <= 2,
Count[Select[list, # > 31 &], _Integer] >= 1,
Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3]
Block[{n = 0, list},
Reap[While[n < 5, list = Sort@RandomSample[Range[36], 7];
If[f[list], n++; Sow[list]]]]][[2, 1]]
答案 1 :(得分:3)
函数f
引用list
作为自由变量而不是参数。虽然这不是一个不可逾越的障碍,但它确实使得打包这个功能变得尴尬,以便它可以在Table
中使用。让我们重新修改这些定义,并在此过程中应用一些简化。
首先,让我们来测试样品是否可以接受:
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]]
原始的主要简化是嵌套的If
语句已被展平为And
条件。新定义还利用Count
可以测试列表值而无需调用嵌套Select
的事实。此外,使用MemberQ[...]
表达了存在性检查。引入了辅助函数来执行可除性检查,以减少主要测试表达式的视觉复杂性。请注意,原始可分性检查错误地返回了一个预期布尔值的列表。已移除_Integer
头部测试,但如果认为需要,可以通过将每个n_
更改为n_Integer
来重新引入这些测试。
现在我们只需要一种在循环中生成样本的方法,直到找到可接受的样本:
generateSample[] :=
While[
True
, RandomSample[Range[36], 7] /.
s_ :> If[acceptableQ[s], Return[Sort @ s]]
]
现在可以使用 generateSample[]
生成一个包含所需结果的表格:
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}}
概括模式
generateSample
中体现的模式可以参数化,以接受任意生成器和过滤器函数:
SetAttributes[generatorSelect, HoldFirst]
generatorSelect[generator_, predicate_] :=
While[True, generator /. s_ :> If[predicate[s], Return[s]]]
generator
参数以未评估的形式保存,以便可以在每次循环中重新评估。因此可以使用这个新功能:
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}}
新功能的优点是它可以与任何发生器和滤波器功能一起使用。这里我们生成三个整数的元组,总计为七个。
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}}
作为一种风格问题,有些人宁愿避免使用Hold
属性定义函数,除非绝对必要。 generatorSelect2
反映了设计选择:
generatorSelect2[generator_, predicate_] :=
While[True, generator[] /. s_ :> If[predicate[s], Return[s]]]
这和generatorSelect
之间的唯一区别是第一个参数现在应该计算为函数:
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}}
答案 2 :(得分:2)
您可以使用Reap
和Sow
:
n = 1; Last@Last@Reap@While[n < 4, Sow[n++]]
(*=> {1, 2, 3}*)
我还建议您查看NestWhileList
:它可能非常适合您的需求。
答案 3 :(得分:2)
这没关系。注意使用SameQ(===)来比较可能的混合类型,列表和布尔值。例如。 {4, 7, 17, 22, 25, 27, 34} == False
未评估。
f := If[1 <= Count[Select[list, # <= 12 &], _Integer] <= 2,
If[Count[Select[list, # > 31 &], _Integer] >= 1,
If[Count[Select[list, Divisible[#, {2, 7}] &], _Integer] <= 3,
Sort[list], False], False], False]
g := (list = RandomSample[Range[36], 7];
While[f === False, list = RandomSample[Range[36], 7];
If[list === f, f]];
f)
Table[g, {9}]