有一种简单的方法可以在 AppleScript 中随机播放列表吗?
我做了几次搜索并画了一个空白。
Fisher-Yates 算法的较短版本:
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)
There are i * ... * 2 = i! possible sequences of random numbers. All of them correspond to exactly one permutation out of the i! permutations of the list.
A faster version that uses a script object:
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
The scripts took about:
So the first script had exponential time complexity. The scripts posted by regulus were slightly slower.
When I saved the first script as scpt and added 10000 elements to the list, I ran into a limit for the number of items that can be saved in a compiled script.
我想我已经破解了。封装在一个功能中以便于使用。
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
这是一个替代方案。我们不是“洗牌”列表,而是随机从列表中抓取项目并将它们插入到新列表中......
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
如果您的新列表中的项目不必是唯一的,那么您可以使用非常有效的
set selectedItemVar to some item of list someItemListVar
I'll just throw in my solution. I'm personally only working with very short lists (about 200 items), from which I need to extract unique, random sublists of various lengths. Applying this algorithm to a list in its entirety (i.e. passing in count of mainList
for maxCount
) will result in a shuffled version of the original list. This isn't built for speed, but may be more accessible to those who aren't strong in algorithms.
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