2011-10-15 18 views
2

我曾在Mathematica中的一個隨機數發生器,受到一些條件的抑制。現在我的代碼如下所示:雖然在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 

它是建立這樣的:

  1. 1-36由
  2. F中的間隔7個整數隨機列表定義了一些條件必須滿足:1-12範圍內至少有一個,最多兩個元素。至少有一個大於31的元素。至多3個元素可以是整數範圍2-7中的整數。
  3. 如果條件滿足,f等於列表,否則爲False。
  4. 接下來是「While」循環。如果f是False,那麼我產生一個新的列表,並且這個循環繼續直到f i不再是False。
  5. 存儲在f中的結果被調用。

現在的事情是:這隻產生一行輸出。我有興趣獲得多個輸出,例如5-10。我試圖用Table命令以某種方式做到這一點,但事實是沒有同時定義函數f和while循環。所以,通過在f上運行表,我只能獲得相同的結果很多次。

關於如何在這裏進行的任何輸入?

+0

書面,在while循環的最後一行不會做任何事情,因爲後面的';'會壓制輸出。當循環選擇一個匹配你想要的條件的列表時,循環後面的'f'將返回所選擇的列表。 – rcollyer

回答

3

函數flist作爲自由變量而不是參數。雖然這不是一個無法克服的障礙,但它的確讓這個功能包裝起來很尷尬,所以它可以在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圖案可以b ë參數接受任意發生器和濾波器功能:

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}} 
+0

更新:我簡化了'!FreeQ [...]'使用'MemberQ [...]'的功能 - 不知道我第一次想到的是什麼。此外,我糾正了導致不正確的可分性測試的拼寫錯誤('divisible2To7' - >'divisible2to7',哦,無類型語言的危害)。 – WReach

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}] 
4

我不認爲你的定義f的第三行正在做你認爲它正在做的事情。考慮例如

Divisible[20, {2, 7}] 

返回{True, False},也不TrueFalse。這意味着 Select[list, Divisible[#, {2, 7}] &]將始終返回一個空列表並且 Count[Select[list, Divisible[#, {2, 7}] &], _Integer] 將始終返回0

如果我正確地解釋了名單的條件,你也可以使用類似

Count[Select[list, Or @@ Divisible[#, Range[2, 7]] &], _Integer] <= 3 

有了這個和阿列克西的建議,使用SowReap,你可以不喜歡

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 = [email protected][Range[36], 7]; 
    If[f[list], n++; Sow[list]]]]][[2, 1]] 
+0

我完全同意考慮可分割命令的條件 - 我簡單地忽略了這一點!非常感謝您使用Sow和Reap的建議。想到這些,但從來沒有工作! – thesixmax