Posts: 9
Threads: 3
Joined: Nov 2017
09-04-2018, 01:28 AM
(This post was last modified: 09-04-2018, 02:40 AM by sirpipthegreat.)
I could probably write something using [random.choice] in python easier than in QM, but wanted to know if there's a way to return values from a weighted dictionary without reinventing the wheel. I'm passing the results back to a QM dialog, so i'd rather not have to package in python dependencies on work computers if i could avoid it.
Ideally, the array would have two dimensions, result and weight, but be dynamic so that updates could be made to the dictionary without recompiling in QM.
Percents would work, but it would also be preferable if it didn't need to add to 100%
;; dictionary fruit.txt would have several arrays similar to this:
{
"apple", 9
"pear", 1
"banana", 10
"orange", 20
}
When ran on this set, apple should be the result 9/40 times, pear 1/40, banana 10/40, and orange 20/40.
If it is going to be a nightmare to do in QM, i will use python and deal with it..
All of the users here are brilliant and way more experienced than i am, so i thought i would ask if there's a simple way to do this (before i pull out any more hair).
Thank you all.
Posts: 117
Threads: 5
Joined: Nov 2015
I'm not sure what you really want, but try this to see if it fits:
Macro Weighted Random Choice
;dictionary fruit.txt would have several arrays similar to this:
;{
;"apple", 9
;"pear", 1
;"banana", 10
;"orange", 20
;}
;Suppose the file dictionary fruit.txt is in the "Desktop" folder.
;You could change the directory to where the file is actually belongs to.
str s1.getfile("$desktop$\fruit.txt")
;Create an IStringMap variable to hold the result and weight values.
IStringMap m._create
lpstr fruit_mapping=sub.createDictMapping(s1)
;Assigned fruit list to IStringMap
m.AddList(fruit_mapping)
;Retrieve the result
out
ARRAY(str) allKeys, allValues
m.GetAll(allKeys, allValues)
int i, sum
for i 0 allValues.len
,sum +=val(allValues[i])
for i 0 allKeys.len
,_s = allKeys[i]
,out F"{_s} = {m.Get(_s)}/{sum}"
#sub createDictMapping
function~ $dict
str line
foreach line dict
,if(line = "{") continue
,if(line = "}") continue
,line.findreplace("''" "" 8)
,line.findreplace("," "" 8)
,_s.addline(line)
ret _s
Posts: 9
Threads: 3
Joined: Nov 2017
09-05-2018, 09:05 PM
(This post was last modified: 09-05-2018, 09:07 PM by sirpipthegreat.)
Thanks for your response! I didn't even think about IStringMap. That will be super helpful in for holding the array dictionary.
The end result was to have it only return one value.
I was giving an example of how often the result would appear with the 1/40. (2.5%) but wanted it to be dynamic so that if you added grapes to the list with a weight of 100, pear would go down to 1/140 (~0.7%)
I think you're onto something with summing them up. I'm just not sure how to do a RandomInt of the sum and get them to cooperate with their weights.
The super inefficient way would be to populate an array with each item a number of times equal to their weight, then pull a random line. That would make sure that pears would only be in the list once, apples would be in there nine times, and so on... so there would be a higher chance for RandomInt to pick apples than pears.
in python it would be:
random.choices([apple,pear,banana,orange],[9,1,10,20])
I was hoping to be able to recreate this function in QM.
Posts: 1,337
Threads: 61
Joined: Jul 2006
09-06-2018, 02:26 AM
(This post was last modified: 09-06-2018, 02:28 AM by Kevin.)
not really offering a solution as of yet but did you by chance see this topic
now it's only 2 choices but may give you an idea on how to proceed further.
http://www.quickmacros.com/forum/showthr...6#pid31186
Posts: 135
Threads: 33
Joined: Aug 2009
09-06-2018, 03:25 AM
(This post was last modified: 09-06-2018, 11:49 PM by AlexZ.
Edit Reason: Some minor changes
)
Hello!
Please, try this:
Macro Use WeightedRandomChoices
lpstr T=
;apple 9
;pear 1
;banana 10
;orange 20
out
out WeightedRandomChoices(T)
Function WeightedRandomChoices
;/
function'str lpstr'T
str s s1
int i
ARRAY(str) a
foreach s T
,s.trim
,if findrx(s "\d+$" 0 2 s1)<0
,,end F"line: '{s}' needs a number"
,s.findreplace(s1)
,for i 0 val(s1)
,,a[]=s
a.shuffle
ret a[0]
Regards
Posts: 1,337
Threads: 61
Joined: Jul 2006
09-06-2018, 06:42 AM
(This post was last modified: 09-06-2018, 07:14 AM by Kevin.)
here is a working weighted random choice code
Alex i borrowed a few lines from yours and adapted it to made it work for the weights.
output shows the random order and the number of times each item was chosen.
lines 23-35 are there just to show the weighted count is correct. You can remove them
Function WeightedRandomChoice
int apples pears bananas oranges
str ss=
;apple 9
;pear 1
;banana 10
;orange 20
str s s1
int i
foreach s ss
,s.trim
,if findrx(s "\d+$" 0 2 s1)<0
,,end F"line: '{s}' needs a number"
,s.findreplace(s1)
,ARRAY(str) a
,for i 0 val(s1)
,,a[]=s
for i a.len-1 -1 -1
,a.shuffle
,_s=a[i]
,_s.trim
,out _s
,a.remove(i)
,sel _s
,,case "apple"
,,apples+1
,,case "pear"
,,pears+1
,,case "banana"
,,bananas+1
,,case "orange"
,,oranges+1
out apples
out pears
out bananas
out oranges
Posts: 9
Threads: 3
Joined: Nov 2017
You dudes are always so rad.
These were as simple and elegant as i had hoped. My arrays might end up being thousands of elements long, so mileage may vary for response time, but you nailed it.
Thank you!
|