有一种简单的方法可以在AppleScript中混洗List吗?

时间:2013-03-17 08:08:11

标签: applescript

有一种简单的方法可以在AppleScript中混洗列表吗?

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

5 个答案:

答案 0 :(得分:2)

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)

有i * ... * 2 =我!可能的随机数序列。所有这些都恰好对应于i中的一个排列!列表的排列。

使用脚本对象的更快版本:

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

脚本采用了:

  • 1000个元素的0.15和0.06秒
  • 12和0.5秒,10000个元素
  • 976秒,100000个元素为4秒

所以第一个脚本具有指数时间复杂度。 regulus发布的脚本略慢。

当我将第一个脚本保存为scpt并将10000个元素添加到列表中时,我遇到了limit for the number of items that can be saved in a compiled script

答案 1 :(得分: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

答案 2 :(得分: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

答案 3 :(得分:0)

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

set selectedItemVar to some item of list someItemListVar

答案 4 :(得分: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