Quick Links: Download Gideros Studio | Gideros Documentation | Gideros community chat | DONATE
Use # for a multi-dimensional table? — Gideros Forum

Use # for a multi-dimensional table?

rpallenrpallen Member
edited November 2017 in General questions
This is a pretty simple question, but I just don't know the answer. I’m not sure how to use “#” in a for loop.

I have a 2 dimensional array, questions(a)(b). The first index (a) indicates the number of the question. The first element of the second index (b) is the text of the question (which is a multiple choice question) and the following elements are the possible answers.

For example (This is for the sixth question in the table.)
questions[6] [question] = “What year was the Declaration of Independence signed?”
questions[6] [correctAnswer] = “1776”
questions[6] [wrongAnswer1] = “1917”
questions[6] [wrongAnswer2] = “1812”
questions[6] [wrongAnswer3] = “1865”
questions[6] [wrongAnswer4] = “1945”

I want to run these questions through a for loop based solely on the first index. That is, I want the loop to do something to the first question, then the same thing to the second and so on. If it was a one dimensional array, I would just do for i=1,#questions, with #questions returning the number of questions. However, I suspect #questions counts all of the elements in the table. If each question has 1 question and 4 answers (i.e, the second index would have possibilities 1-5) #questions would return a number that is 5 times the number of questions in the table. Is this correct?

If I knew for sure that every question had 5 elements as in the example above, I could just use #questions/5 instead of #questions. But some questions only have 3 choices, not 4, so there’s no way I could do that.

Is there a way to get the number of elements in each of the dimensions of the table?
For example (a is the number of elements in first dimension and b is the number of elements in the second dimension):
for i=1,a do
for j=1,b do
code to be performed
end
end

That is, what can I use in my code in place of a and b to loop through the number of items in each dimension of the table?

Comments

  • assuming you have questions in a table from 1 to n, you can use # to find the number of entries in the table. Then assuming each question has a sub-table that doesn't use numbers to index it then you can use in pairs. Here is an example...
    for loop=1,#questions do
      local question=questions[loop]
      for key,value in pairs(question) do
        print(key,value)
      end
    end

    Likes: antix

    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
    +1 -1 (+1 / -0 )Share on Facebook
  • Thanks, SinisterSoft.

    Likes: SinisterSoft

    +1 -1 (+1 / -0 )Share on Facebook
  • No problem. :)
    Coder, video game industry veteran (since the '80s, ❤'s assembler), arrested - never convicted hacker (in the '90s), dad of five, he/him (if that even matters!).
    https://deluxepixel.com
  • piepie Member
    edited November 2017
    @rpallen just a couple of notes from my personal experience to integrate SinisterSoft's answer:

    pairs is wonderful, but "slow". maybe you won't notice that in this app because you run it only once in a while. However watch out for performance if you need to "abuse" of it :) also note that pairs outcome may vary its order (somewhere someone made a pairsByKeys lua function to avoid this, but it's even slower because it has to check and order elements before returning them).
    Usually nested for loops are performance killers, but sometimes you can't avoid this.

    However the fastest way to operate on tables with for loops is using numerical indices.
    for loop=1,#questions do

    The lenght operator # works only on strings (ie. to know how many chars are there) and on tables with numerical indices.
    You may experience strange behaviours -like 0 counts- if your table has string indices (or mixed string and number indices).

    I think that I personally would write my questions and answers with numerical indices, in a way that the question and the correct answer are always in the same place (index), and my app knows that.
    ie:

    questions[6] = {
    “What year was the Declaration of Independence signed?”,
    “1776”,
    “1917”,
    “1812”,
    “1865”,
    “1945”
    }

    [1] the question
    [2] the correct answer
    how many answers are there = #questions[6] - 1
    (where the 1 we are taking away is the first table entry, because it is the question in this scenario, but it could also have been the last..., so that questions[6][ #questions[6] ] was the question)

    or

    questions[6] = {
    q = “What year was the Declaration of Independence signed?”,
    a = {
    “1776”,
    “1917”,
    “1812”,
    “1865”,
    “1945”
    }
    }

    [q] the question
    [a] the answers, [a][1] is the correct one.
    how many answers are there = #questions[6][a]

    Both ways would enable to check how many answers are there with the lenght operator, then I would mix the answers on a random basis when placing them on screen (but here I suppose I would still need for and maybe pairs. Just once though, when I need to place the answers on screen) .

    Another option would be to add a "correct answer" value to each questions entry:
    questions[6]["c"] = 1 (assuming that the right answer is on index 1) to tell the app which answer is correct (which index inside "a" contains the right answer), in this way you won't need to mix the answers, because you can write them already in the order you like. But everytime you play, the answers would be in the same position.

    edit: i forgot to answer this
    If each question has 1 question and 4 answers (i.e, the second index would have possibilities 1-5) #questions would return a number that is 5 times the number of questions in the table. Is this correct?
    no, assuming you have questions in a table from 1 to n (using numerical indices), # would return n .
    If you have one (or more) sub-tables their value would always count 1 each (# just counts each entry at the "table level" you ask. see my examples before)
  • rpallenrpallen Member
    edited November 2017
    Thanks, pie.

    I do use two randomizing functions, one to randomize the questions and another to randomize the answers. I need 2 functions because they need to operate a bit differently. The one for the answers has to both randomize the order of the answers and keep track of the position of the correct answer. The randomizer for the questions only needs to randomize the order of the questions.
  • piepie Member
    edited November 2017
    @rpallen I thought that you could even build your question as:

    questions[6] = {
    q = “What year was the Declaration of Independence signed?”,
    a = {
    {“1776”},
    “1917”,
    “1812”,
    “1865”,
    “1945”
    }
    }

    in this way you could use the same function for both "randomize" operations, without the need to keep track of the correct answer position.
    You may get the correct answer just looking at the data type:
    local output 
    for n=1, #questions[6][a] do
     if type(questions[6][a][n]) == 'table' then
      --this is the correct answer
      output = questions[6][a][n][1] 
     else 
      --this is a wrong answer
      output = questions[6][a][n]
     end
    end
  • antixantix Member
    edited November 2017
    What about just keeping track of which question is correct?
    questions = {
      {
        question = “What year was the Declaration of Independence signed?”,
        answers = {
          {text =1776”, correct = true},
          {text =1917”, correct = false},
          {text =1812”, correct = false},
          {text =1865”, correct = false},
          {text =1945”, correct = false},
        },
      },
    -- more questions here
    }
  • antixantix Member
    edited November 2017
    Got bored eating breakfast so this is kind of what I was eluding to above..
    local questions = {
      {
        question = "What year was the Declaration of Independence signed?",
        answers = {
          "1776", -- always put the correct answer first in the list
          "1917",
          "1812",
          "1865",
          "1945",
        },
        order = {}, -- the random order of the answers is stored here
      },
    -- more questions here
    }
     
    -- randomly order all questions
    local function randomizeAnswers(questions)
      local insert, remove, random = table.insert, table.remove, math.random
     
      for q = 1, #questions do
        local question = questions[q] -- next question to order randomly
     
        local available = {}
        local order = {} -- we will store our order here
     
        -- generate the default order  
        local numQuestions = #question.answers
        for i = 1, numQuestions do
          insert(available, i)
        end
     
        -- generate the randomized order
        for i = 1, numQuestions do
          local n = random(1, #available) -- throw a random number from 1 to the number of available answers
          insert(order, remove(available, n)) -- remove the randomly chosen answer and add it to the order list
        end
     
        question.order = order -- save the new random order
      end
    end
     
    for i = 1, 9 do
      randomizeAnswers(questions) -- mix them up
     
      local question = questions[1] -- print out the results
      local order = question.order
      local s = ""
      for i = 1, #order do
        s = s .. order[i] .. ", "
      end
      print(s)
    end

    Likes: pie

    +1 -1 (+1 / -0 )Share on Facebook
  • antixantix Member
    edited November 2017
    Actually in my example above you wouldn't even need to have the bool to signify which answer was correct. Instead always put the correct answer as the first in the answer list as the order they will be displayed will always be random :)

    EDIT: Updated the above code to support this theory ;)
Sign In or Register to comment.