Это простой способ перетасовать список в AppleScript?Это простой способ перетасовать список в AppleScript?
Я сделал несколько поисков и нарисовал пробел.
Это простой способ перетасовать список в AppleScript?Это простой способ перетасовать список в AppleScript?
Я сделал несколько поисков и нарисовал пробел.
Сокращенный вариант алгоритма Фишера-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)
Есть я * ... * 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
Сценарии приняли около:
Итак, первый сценарий имел экспоненциальную временную сложность. Сценарии, опубликованные регулусом, были немного медленнее.
Когда я сохранил первый скрипт как scpt и добавил в список 10000 элементов, я столкнулся с 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
Это фактически алгоритм Фишера-Йейта. Алгоритм Саттоло будет иметь «случайное число от 1 до listLength - 1», и он производит только перестановки, которые являются циклами (он будет изменять только {1, 2, 3} до {2, 3, 1} или {3, 1, 2 }). – user495470
Вот альтернатива. Вместо того, чтобы «перетасовка» список, мы просто случайно захватить элементы из списка и вставить их в новый список ...
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
EDIT: если вы хотите, чтобы ускорить действия по большому списку вы можете использовать объект сценария. Вы часто увидите увеличение скорости при большом списке. Таким образом, вы могли бы написать ваш код таким образом, используя объект сценария ...
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
Я новичок в applescript, является ли вышеупомянутый метод более эффективным, чем мое собственное решение? – regnix
Я не знаю об эффективности, но я бы поспорил, что все ваши номера не двигаются.Например, вы получаете 10 случайных чисел от 1 до 10. Поскольку они случайны, вы, вероятно, не получаете каждого номера (некоторые числа будут повторяться), поэтому в вашем коде не будет вызываться каждый элемент. В моем коде я удаляю элемент из списка, а затем получаю еще один случайный элемент, пока не получу все из них. Таким образом, мой код действует на каждый элемент списка. Поэтому вы решаете, какой метод лучше всего подходит для вашей ситуации. Я просто хотел показать вам альтернативу. Они оба смешивают их до некоторой степени. – regulus6633
Спасибо за ответ. Мне просто интересно, как на каждом языке я всегда заканчивал перетасовку массивов/списков в какой-то момент и искал хороший фрагмент для закладки для applescript. Мой код является прямой копией алгоритма Саттоло из Википедии и работает для меня. Я был обеспокоен эффективностью, потому что я перетасовываю списки около 3000 предметов на данный момент и ожидаю, что это будет намного больше в финальной версии моего текущего проекта. (И вы ВСЕГДА должны перетасовать пару раз, как вы знаете, что такое «случайные» номера на компьютерах;)) – regnix
Если элементы в вашем новом списке не должны быть уникальными, то вы могли бы использовать очень эффективно
set selectedItemVar to some item of list someItemListVar
Я просто брошу свое решение. Я лично работаю только с очень короткими списками (около 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
Можете ли вы объяснить вторую последнюю строку, 'l of s'? –
На самом деле, можете ли вы описать, как работает 'set {item i of of of s, item j of of of s} на {item j of of of s, item i of of of l}? –