After checking Shane’s code for the framework “GameplayKit”
I made Apple’s example in Objective-C to ASOC.
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
(** Objective-C
* Reference: https://developer.apple.com/documentation/gameplaykit/gkgaussiandistribution?language=objc
* GKRandomSource *random = [[GKRandomSource alloc] init];
* GKRandomDistribution *dice3d6;
* dice3d6 = [[GKGaussianDistribution alloc]
* initWithRandomSource:random lowestValue:3 highestValue:18];
* // Roll the dice...
* int diceRoll = [dice3d6 nextInt];
*)
set randomSource to current application's GKRandomSource's alloc()'s init()
set dice3d6 to current application's GKGaussianDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:3 highestValue:18
return (dice3d6's nextInt()) as integer
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:6
-- return (shuffled's nextInt()) as integer
-- Log the output of 100
set shuffleDist to current application's GKShuffledDistribution's d6
repeat with i from 1 to 100
log {shuffleDist's nextInt() as integer}
end repeat
-- Reference: https://developer.apple.com/documentation/gameplaykit/gkrandomsource/1501128-arraybyshufflingobjectsinarray
-- Returns an array whose contents are the same as those of the specified array, but in a random order determined by the random source.
set theArray to {1,2, 3, 4, 5, 6, 7, 8, 9}
set theArray to current application's NSArray's arrayWithArray:theArray
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
return shuffled as list
set randomSource to current application's GKRandomSource's alloc()'s init()
set randItem to current application's GKRandomDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:c
(randItem's nextInt()) as integer
I would like to use
func nextInt(upperBound: Int) → Int
I dont know how to write it correctly in AppleScriptObjC
Thanks Fredrik71 for the thread. I wanted to learn a bit about getting random numbers with ASObjC and this was a good starting point.
A more particular goal of my research was to settle on an ASObjC script that returns a specific number of random numbers from a particular range of numbers. In the end, I settled on Shane’s second script below–it’s fast and compact, and it is sufficiently random for my needs.
-- Shane 1 - 42 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set x to current application's GKARC4RandomSource's sharedRandom()
set theList to {}
repeat 1000 times
set end of theList to x's nextIntWithUpperBound:1000
end repeat
count theList --> 1000
-- Shane 2 - 21 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set x to current application's GKRandomDistribution's distributionWithLowestValue:1 highestValue:1000
set theList to {}
repeat 1000 times
set end of theList to x's nextInt()
end repeat
count theList --> 1000
-- From this thread - 22 milliseconds
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theList to {}
set randomSource to current application's GKRandomSource's alloc()'s init()
set randomItem to current application's GKRandomDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:1 highestValue:1000
repeat 1000 times
set end of theList to randomItem's nextInt()
end repeat
count theList --> 1000
-- Basic AppleScript -- 88 milliseconds (remove comment)
set theList to {}
repeat 1000 times
# set end of theList to random number from 1 to 1000
end repeat
count theList --> 1000
Thread with Shane’s scripts:
BTW, there are occasions where I want to create a shuffled list of numbers with a specific range, and I think the following may be the way to do this. The timing result to create a list of 1,000 numbers was 24 milliseconds.
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set startNumber to 1
set endNumber to 10
set theList to {}
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:randomSource lowestValue:startNumber highestValue:endNumber
repeat endNumber times
set end of theList to shuffled's nextInt()
end repeat
theList --> {9, 10, 8, 2, 3, 5, 4, 7, 6, 1}
@peavine
Your code will call at least 12 times to bridge objective-c call, I know there have been talk in this forum about doing many calls to objective-c in repeat loop. become slower and vanilla AppleScript. Only a reminder… :), thanks for the regard about this topic.
When this code will only do 3 I think.
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set theArray to {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
set theArray to current application's NSArray's arrayWithArray:theArray
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
return shuffled as list
Fredrik71. I tested the following script which involved no bridging, and it took almost twice as long to run with both scripts set to create and shuffle 1000 numbers (45 milliseconds versus 24 milliseconds).
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
set startNumber to 1
set endNumber to 1000
set theShuffledNumbers to current application's NSMutableArray's new()
set theShuffledSource to current application's GKShuffledDistribution's alloc()'s initWithRandomSource:(current application's GKRandomSource's alloc()'s init()) lowestValue:startNumber highestValue:endNumber
repeat endNumber times
theShuffledNumbers's addObject:(theShuffledSource's nextInt())
end repeat
return theShuffledNumbers as list
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
generateListC(1000)
on generateListC(x as integer) -- "BEST" so far (COCOA)
local i, theArray, randomSource, shuffled
script M
property nlist : {1}
end script
repeat with i from 2 to x
set end of M's nlist to i
end repeat
set theArray to current application's NSArray's arrayWithArray:(M's nlist)
set randomSource to current application's GKRandomSource's alloc()'s init()
set shuffled to randomSource's arrayByShufflingObjectsInArray:theArray
return shuffled as list
end generateListC
And here is a slightly shorter one - same speed
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "GameplayKit"
use scripting additions
generateListC(1000)
on generateListC(x as integer) -- "BEST" so far (COCOA)
local i, theArray, randomSource, shuffled
script M
property nlist : {1}
end script
repeat with i from 2 to x
set end of M's nlist to i
end repeat
set theArray to current application's NSArray's arrayWithArray:(M's nlist)
set shuffled to theArray's shuffledArray() as list
return shuffled as list
end generateListC
BTW, there are actually two topics dealt with in this thread, which are getting a random list and a shuffled list. I referenced one of Shane’s posts above on getting a list of random numbers with ASObjC; a post by Shane on getting a shuffled list with ASObjC is at:
My rewrite of Shane’s suggestion to shuffle an existing list is:
use framework "Foundation"
use framework "GameplayKit"
set theList to {"a", "b", "c", "d", "e"}
set randomSource to current application's GKMersenneTwisterRandomSource's new()
# set randomSource to current application's GKARC4RandomSource's new() -- an alternative
set shuffledList to randomSource's arrayByShufflingObjectsInArray:theList
return shuffledList as list
# Documentation:
# GKMersenneTwisterRandomSource. A basic random number generator implementing the Mersenne Twister algorithm, which is more random, but slower than the default random source.
On occasion, the user may want to get a shuffled list of numbers in a specified range (say 1 to 1000). This can be done with the GKShuffledDistribution class (48 milliseconds) but it’s much faster simply to create a list of numbers with a repeat loop and then to use Shane’s above suggestion (3 milliseconds total). This is also the approach taken by Robert and it works great
To store a value in memory is slower and to get a value that alredy excist in memory.
In other words the time it takes to read data in memory is lower and it would be to write
to memory with some data.
In your case it doesn’t matter, but it could matter alot for app that emulate something.
Take rosetta some example… first run it takes time, next run its faster…
To give other example. I show here on macscripter how I could search text content from more and 15000 files in less and 3 seconds. And that was on my old computer from 2012.
The way I did it… I load the contents from file and did the search on the data. Instead of having Finder or other ways to search the disk for files. In other words it was faster to set the location of some files and it would be to read it first and next do search on its contents.