首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Mathematica中的While循环:多个输出

Mathematica中的While循环:多个输出
EN

Stack Overflow用户
提问于 2011-10-15 11:03:14
回答 4查看 3.2K关注 0票数 2

我研究过数学中的随机数发生器,它被一些条件所抑制。现在,我的代码如下所示:

代码语言:javascript
复制
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

它是这样建立起来的:

  1. 由区间1-36的7个整数组成的随机列表
  2. f定义了一些必须满足的条件:在1-12范围内至少有一个元素,最多两个元素。至少一个大于31的元素。最多3个元素可以被2-7范围内的整数整除。如果满足条件,f等于列表,则假otherwise.
  3. Next ( False
  4. )是"While“循环。如果f是False,那么我生成了一个新的列表,这个循环一直持续到f不再为False为止。
  5. 存储在f中的结果称为.

现在的情况是:这只产生一行输出。我对获得多个输出感兴趣,例如5-10。我尝试用Table命令以某种方式完成这个任务,但问题是,没有任何东西同时定义函数f和while循环。所以,通过在f上运行表,我只得到了很多次相同的结果。

有关于如何在这里进行的任何投入吗?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-10-15 17:31:27

函数flist引用为空闲变量,而不是参数。虽然这不是一个无法克服的障碍,但将此功能打包以便在Table中使用确实让人感到尴尬。让我们重新研究这些定义,并在此过程中应用一些简化。

首先,让我们处理一个样本是否可以接受的测试:

代码语言:javascript
复制
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来重新引入它们。

现在,我们只需要一种在循环中生成样本的方法,直到找到一个可接受的示例:

代码语言:javascript
复制
generateSample[] :=
  While[
    True
  , RandomSample[Range[36], 7] /.
      s_ :> If[acceptableQ[s], Return[Sort @ s]]
  ]

现在可以使用generateSample[]生成一个表,表中包含所需的结果:

代码语言:javascript
复制
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中包含的模式可以参数化,以接受任意生成器和筛选函数:

代码语言:javascript
复制
SetAttributes[generatorSelect, HoldFirst]
generatorSelect[generator_, predicate_] :=
  While[True, generator /. s_ :> If[predicate[s], Return[s]]]

generator参数保持在未计算的形式,因此可以在每次遍历循环时重新计算。因此,这一新功能可用于:

代码语言:javascript
复制
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。

代码语言:javascript
复制
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反映了这种设计选择:

代码语言:javascript
复制
generatorSelect2[generator_, predicate_] :=
  While[True, generator[] /. s_ :> If[predicate[s], Return[s]]]

这与generatorSelect之间的唯一区别是,第一个参数现在被期望计算为一个函数:

代码语言:javascript
复制
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}}
票数 3
EN

Stack Overflow用户

发布于 2011-10-15 11:55:36

我不认为f定义的第三行是做您认为它正在做的事情。例如,考虑

代码语言:javascript
复制
Divisible[20, {2, 7}]

它返回{True, False},而不是TrueFalse。这意味着Select[list, Divisible[#, {2, 7}] &]总是返回一个空列表,而Count[Select[list, Divisible[#, {2, 7}] &], _Integer]总是返回0

如果我正确地解释了列表的条件,您可以使用类似的

代码语言:javascript
复制
Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3

有了这个和Alexy关于使用SowReap的建议,您可以做一些类似的事情

代码语言:javascript
复制
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]]
票数 4
EN

Stack Overflow用户

发布于 2011-10-15 11:18:56

为此,可以使用ReapSow

代码语言:javascript
复制
n = 1; Last@Last@Reap@While[n < 4, Sow[n++]]

(*=> {1, 2, 3}*)

我还建议查看NestWhileList:可能会发现它非常适合您的需要。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7777397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档