Search code examples
randomlua

Lua - Choose a random value from a range (or table) excluding the values of a (or another) table


A range, 1, 2, 3, 4, 5, 6, 7, 8 (it can populate a Lua table if it makes it easier)
table = {1, 4, 3}

The possible random choice should be among 2, 5, 6, 7, 8.

In Python I have used this to get it:

possibleChoices = random.choice([i for i in range(9) if i not in table])

Any ideas how to achieve the same in Lua?


Solution

  • Lua has a very minimal library, so you will have to write your own functions to do some tasks that are automatically provided in many other languages.

    A good way to go about this is to write small functions that solve part of your problem, and to incorporate those into a final solution. Here it would be nice to have a range of numbers, with certain of those numbers excluded, from which to randomly draw a number. A range can be obtained by using a range function:

    -- Returns a sequence containing the range [a, b].
    function range (a, b)
      local r = {}
      for i = a, b do
        r[#r + 1] = i
      end
      return r
    end
    

    To get a sequence with some numbers excluded, a seq_diff function can be written; this version makes use of a member function:

    -- Returns true if x is a value in the table t.
    function member (x, t)
      for k, v in pairs(t) do
        if v == x then
          return true
        end
      end
      return false
    end
    
    -- Returns the sequence u - v.
    function seq_diff (u, v)
      local result = {}
      for _, x in ipairs(u) do
        if not member(x, v) then
          result[#result + 1] = x
        end
      end
      return result
    end
    

    Finally these smaller functions can be combined into a solution:

    -- Returns a random number from the range [a, b],
    -- excluding numbers in the sequence seq.
    function random_from_diff_range (a, b, seq)
      local selections = seq_diff(range(a, b), seq)
      return selections[math.random(#selections)]
    end
    

    Sample interaction:

    > for i = 1, 20 do
    >> print(random_from_diff_range(1, 8, {1, 4, 3}))
    >> end
    8
    6
    8
    5
    5
    8
    6
    7
    8
    5
    2
    5
    5
    7
    2
    8
    7
    2
    6
    5