2013-03-17 42 views

回答

2

較短版本的費雪耶茨算法:

on shuffle(l) 
    set i to count of l 
    repeat while i ≥ 2 
     set j to random number from 1 to i 
     tell l to set {item i, item j} to {item j, item i} 
     set i to i - 1 
    end repeat 
    l 
end shuffle 

set l to {} 
repeat 1000 times 
    set end of l to random number from 1 to 1000 
end repeat 
shuffle(l) 

有我* ...... * 2 =我!可能的隨機數字序列。它們全部對應於我的一個排列!列表的排列。

一個使用腳本對象的更快版本:

on shuffle(input) 
    script s 
     property l : input 
    end script 
    set i to count of l of s 
    repeat while i ≥ 2 
     set j to random number from 1 to i 
     set {item i of l of s, item j of l of s} to {item j of l of s, item i of l of s} 
     set i to i - 1 
    end repeat 
    l of s 
end shuffle 

腳本歷時約:

  • 0.15和0.06秒1000個元素
  • 12和0.5秒10000個元件
  • 對於100000個元素,976秒和4秒

所以第一個腳本具有指數時間複雜性。 regulus發佈的腳本稍微慢一些。

當我將第一個腳本保存爲scpt並將10000個元素添加到列表中時,我遇到了limit for the number of items that can be saved in a compiled script

+0

你能解釋倒數第二行嗎? – 2014-11-29 15:14:31

+0

實際上,你能否詳細說明如何設置{s中的項目i,s中的項目j}到{s中的項目j,s中的項目i}作品? – 2014-11-29 15:16:06

1

我想我已經破解了它。包裹在一個易於使用的功能。

set myList to {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 

set answer to listShuffle(myList) 


on listShuffle(theList) 

set listLength to count of theList 

repeat while listLength > 1 



    set r to random number from 1 to listLength 

    set item1 to item listLength of theList 
    set item2 to item r of theList 

    set item listLength of theList to item2 
    set item r of theList to item1 

    set listLength to listLength - 1 

end repeat 

return theList 

end listShuffle 
+0

這實際上是Fisher-Yates算法。 Sattolo的算法將具有從1到listLength-1的隨機數,並且它僅產生作爲週期的排列(它將僅將{1,2,3}改變爲{2,3,1}或{3,1,2} })。 – user495470 2013-03-24 17:56:36

1

這是另一種選擇。而不是「洗牌」列表中,我們只是隨機從列表中搶項目,並把它們插入到一個新的列表...

set myList to {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 
set randomizedList to randomizeList(myList) 

on randomizeList(theList) 
    set listCount to count of theList 

    set newList to {} 
    repeat listCount times 
     set subListCount to count of theList 
     set r to random number from 1 to subListCount 
     set end of newList to item r of theList 

     -- remove the random item from theList 
     if subListCount is 1 then 
      exit repeat 
     else if r = 1 then --> first item 
      set theList to items 2 thru end of theList 
     else if r = subListCount then --> last item 
      set theList to items 1 thru -2 of theList 
     else 
      set theList to items 1 thru (r - 1) of theList & items (r + 1) thru -1 of theList 
     end if 
    end repeat 

    return newList 
end randomizeList 

編輯:如果你想加快的大名單上的行動你可以使用腳本對象。當名單很大時,你會經常看到很大的速度增益。所以,你可以寫你使用腳本對象這樣的代碼......

set myList to {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} 
set answer to listShuffle(myList) 

on listShuffle(theList) 
    script s 
     property l : missing value 
    end script 
    set s's l to theList 

    set listLength to count of s's l 

    repeat while listLength > 1 
     set r to random number from 1 to listLength 

     set item1 to item listLength of s's l 
     set item2 to item r of s's l 

     set item listLength of s's l to item2 
     set item r of s's l to item1 

     set listLength to listLength - 1 
    end repeat 

    return s's l 
end listShuffle 
+0

我是新來的applescript,上面的方法比我自己的解決方案更有效嗎? – regnix 2013-03-17 18:18:21

+1

我不知道更有效率,但我敢打賭,你所有的數字都不會移動。例如,你可以從1到10中得到10個隨機數。因爲它們是隨機的,你可能不會得到每一個數字(有些數字會重複),因此在你的代碼中並不是每個項目都會被調用。在我的代碼中,我從列表中刪除該項目,然後獲得另一個隨機項目,直到我獲得所有項目。因此我的代碼作用於每個列表項。所以你決定哪種方法最適合你的情況。我只是想告訴你一個選擇。他們都混合到一定程度。 – regulus6633 2013-03-17 22:11:56

+0

感謝您的回覆。我只是想知道,因爲在每種語言中,我總是會在某個時候結束洗牌陣列/列表,並正在尋找一個很好的片段來爲applescript添加書籤。我的代碼是來自維基百科的Sattolo算法的直接副本,適用於我。 我很擔心效率,因爲我正在洗牌目前約3,000件商品的清單,並期望它在我目前項目的最終版本中有很多。 (你總是不得不洗牌幾次,因爲你知道計算機上的「隨機」數字是什麼)) – regnix 2013-03-18 01:28:30

0

如果在新列表中的項目不必是唯一的,那麼你可以用非常有效的

set selectedItemVar to some item of list someItemListVar 
0

我只是拋出我的解決方案。我個人只使用非常短的名單(約200項),從中我需要提取各種長度的獨特隨機子列表。將該算法應用於整個列表(即傳入count of mainList,maxCount)將導致原始列表的混洗版本。這不是爲了速度而構建的,但對於算法不強的人可能更容易獲得。

on randomizedSublist(mainList, maxCount) 
    set sublist to {} as list 
    repeat with x from 1 to maxCount 
     set oneItem to some item of mainList 
     repeat until sublist does not contain oneItem 
      set oneItem to some item of mainList 
     end repeat 
     set end of sublist to oneItem 
    end repeat 
    return sublist 
end randomizedSublist 
相關問題