Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
3

Can you pick out items from a dictionary randomly?

Asked by
Legojoker 345 Moderation Voter
8 years ago

Is there any method to pick out answers from a dictionary randomly? Essentially, what I've been using a table such as this:

local tab = {
    ID42 = {
    -- other stuff
    },
    ID74 = {
    -- other stuff
    },
    ID22 = {
    -- other stuff
    }
}

These IDs are given out numerically from 1 to somewhere in the thousands before the round resets the IDs and counter, but are deleted due to circumstances of manipulation during the round. These deletions have no patterns (ie; it's not the least recent ID or something since these IDs represent units in a game that are killed off in fights and other unpredictable events) so therefore I can't just use a math.random() for a set interval. I would love if someone could figure out a way to use math.random() to do this though.

I anticipate an answer such as this:

local tab = {obj = 5, obj2 = 7, obj3 = 9}

local newTab = {}
for _,v in pairs(tab) do
    table.insert(newTab, v)
end

print(newTab[math.random(1,#newTab)])

HOWEVER, I do not want to convert my dictionary into an array of numerical indexes. Can anyone solve this without converting the dictionary? I'd really appreciate it.

2 answers

Log in to vote
4
Answered by 8 years ago

Iterate. Easy, right?
I've had to do this for people before.

To get the length of a dictionary:

function getn(t)
local i = 0;
for k in next,t do
i = i+1;
end;
return i;
end;

To get a random entry:

function trand(t)
local c,i=0,math.random(getn(t));
for k,v in next,t do
c=c+1;
if c == i then
return v
end
end
end

How does it work?
First, we get the length of the dictionary (through iteration), and like a rabbit from a hat we magically procure a random number. Then, we iterate through until we get to the number for that iteration, and return the value it matches.

0
Oh, that's a good idea! It still seems like a pretty expensive call though, especially if you do it a lot, even without a table remake. I'll try to keep the calling minimal. It's better than the other version though, thanks! Legojoker 345 — 8y
Ad
Log in to vote
0
Answered by 8 years ago

Here's how I'd do it

local tab = {1,nil,2,3}

local function ran(t)
   local r = {}
   for i,v in next, t do
      if v then
         table.insert(r,v)
      end
   end
   return r[math.random(1,#r)]
end

If you're calling it repeatedly, then you can define the new table outside of the function. That way you can keep calling for random values repeatedly in the new table.

Answer this question