我研究过数学中的随机数发生器,它被一些条件所抑制。现在,我的代码如下所示:
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上运行表,我只得到了很多次相同的结果。
有关于如何在这里进行的任何投入吗?
发布于 2011-10-15 17:31:27
函数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}}新函数的优点是它可以与任何生成器和过滤器函数一起使用。这里我们生成三个整数的元组,之和为7。
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}}发布于 2011-10-15 11:55:36
我不认为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]]发布于 2011-10-15 11:18:56
为此,可以使用Reap和Sow:
n = 1; Last@Last@Reap@While[n < 4, Sow[n++]]
(*=> {1, 2, 3}*)我还建议查看NestWhileList:可能会发现它非常适合您的需要。
https://stackoverflow.com/questions/7777397
复制相似问题