1

有一种简单的方法可以在 AppleScript 中随机播放列表吗?

我做了几次搜索并画了一个空白。

4

5 回答 5

3

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:

  • 0.15 and 0.06 seconds for 1000 elements
  • 12 and 0.5 seconds for 10000 elements
  • 976 seconds and 4 seconds for 100000 elements

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.

于 2013-03-24T17:55:54.147 回答
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
于 2013-03-17T09:18:54.037 回答
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
于 2013-03-17T11:14:20.023 回答
1

如果您的新列表中的项目不必是唯一的,那么您可以使用非常有效的

set selectedItemVar to some item of list someItemListVar
于 2013-03-18T10:54:53.373 回答
0

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
于 2017-10-06T03:23:35.350 回答