Randomly picking from a dictionary

Since I had occasion to need to pick a random script from a dictionary, I thought I'd put the code I worked out eventually here, as there is no equivalent to the PickOne() function for dictionaries afaik.

Dictionary is keyed with 'one', 'two', etc.

x = GetRandomInt (1, DictionaryCount(this.dictionary))
y = ToWords(x)
foreach (key, this.dictionary) {
  if (y=key) {
    invoke (ScriptDictionaryItem (this.dictionary, y))
  }
}

Adding keys to the dictionary is easy too, just use ToWords and DictionaryCount(this.dictionary)+1 as the new key.


This seems a weird solution.

I can't see any situation in which a dictionary with predefined keys like this would be better than a list. You can always use numeric keys, and then call ToWords on them when you want to display them to the player.

It might be useful to pick a random key from a dictionary in some cases; in which case I'd expect to see something like this:

index = GetRandomInt (1, DictionaryCount(somedictionary))
foreach (key, somedictionary) {
  index = index - 1
  if (index = 0) {
    selected_key = key
    selected_value = DictionaryItem (somedictionary, key)
  }
}

But for the dictionary you describe… why not just use a list?


Because it's a script dictionary, not a string dictionary. I want a random script selected from the dictionary. Why go to the extra step of making a list of the keys to randomly select from?

The exact context is that I want a command to pick a random script from the dictionary to determine the response. So I have the command attribute call the code above and pick a random key from the dictionary to do the script. Not sure how I would do that with lists?


Because it's a script dictionary, not a string dictionary. I want a random script selected from the dictionary. Why go to the extra step of making a list of the keys to randomly select from?

Making an extra list to hold the keys is about 30 times less efficient than just putting the scripts in a list.
Using arbitrary keys to make a dictionary act like a list is around ~120 times less efficient. You're looping over the list every time, which will get bad fast if it's a big list.

Is there any reason not to just put the scripts in a list?

Edit: If you're using the desktop editor, I believe the GUI doesn't give you a way to create a list of scripts. I didn't think of this at first because the web editor has the same problem with scriptdictionarys, so I'm used to working with a bunch of initialisation scripts filled with list add and dictionary add instructions. So if you're working around the limitations of the editor, that kind of makes sense. Although in that case, it still seems more efficient to convert the dictionary to a list on startup rather than jumping through hoops every time you use it.


"If you're using the desktop editor, I believe the GUI doesn't give you a way to create a list of scripts."

This. I didn't even know it was possible to make a list of scripts. How does one go about that? The functions etc in the docs seem to only cover stringlists and objectlists...


As well as stringlists and objectlists, there are untyped lists; created using NewList() and you access items with ListItem(). An untyped list can have any type of data in it, including strings, scripts, objects, numbers, and other lists and dictionaries.

One gotcha is that you can't use the return value of ListItem as an argument to a built-in function.

For example:

if (ListItem (somelist, 0)) {

will give an error, because if requires a boolean argument, and the declared return type of ListItem isn't boolean.

But this:

value = ListItem (somelist, 0)
if (value) {

will work fine, as long as the 0th item in the list is true or false.


Thank you! The docs make it seem like a regular list can still only have strings or objects in them. This does make a lot of sense.


This topic is now closed. Topics are closed after 60 days of inactivity.

Support

Forums