Generic for

From Legacy Roblox Wiki
Revision as of 13:19, 29 January 2012 by >Builder1010101 (Fixed indentation, changed the formats, so they are all <code lua> and changed {{Example|<pre> with "Output: ..." in it to the {{code and output format. Feel free to undo my changes, if they are not satisfactory.)
Jump to navigationJump to search

Introduction

Basic for loops have already been covered in Loops. If you haven't already done so, please review Loops. First, lets take a look at iterators. In layman's terms, an iterator is a function that returns the next set of values each time it is called. Here's a simple iterator:

-- returns an iterator that counts letters between first and last function letterIterator(first, last)

  -- store the position that the iterator is at
  local index = first 
  -- return the iterator - a function!
  return function()
     if index <= last then
        -- move to the next character
        index = index + 1  
        -- return it's ascii representation plus 95
        -- note that there's only one value being returned
        return string.char(index + 95)
     end
  end

end

And here's how we can use it:

local iterator = letterIterator(1, 4) local letter

letter = iterator() print(letter) -- 'a'

letter = iterator() print(letter) -- 'b'

letter = iterator() print(letter) -- 'c'

letter = iterator() print(letter) -- 'd'

letter = iterator() print(letter) -- nil

letter = iterator() print(letter) -- nil

As you can see, the iterator returned the first, second, third, and fourth letters, then stopped returning anything. At this point, there's nothing left to iterate, so you should stop calling the iterator. That's where the generic for loop comes in. We can write the previous code like this instead:

for letter in letterIterator(1, 4) do
   print(letter)
end

a b c

d

Discussion

The iterator is the number that keeps track of how many times a for loop is supposed to run. This is different from a the numeric for loop in Loops in that the numeric for loop there is simply an iterator:

Numeric for: for i = 20, 1, -2 do print(i) end However, in the generic for loop we get the values returned by the iterator function. In the iterator returned by letterIterator() above, we saw that string.char(index + 95), not index itself, was returned. Here's an example using multiple return values:

function doublingIterator(array)
   local i = 1 -- The index in the array we're currently at
   return function()
      -- Make sure we haven't hit the end of the array
      if array[i] ~= nil then
         -- prepare return values
         local index, doubledValue = i, array[i]*2
         -- Add one to i, so that we use the next element next time
         i = i + 1
         return index, doubledValue
      end
   end
end
 
local numbers = {3, 4, 5}
 
-- Two, count 'em, two variables. That's because 2 values are returned!
for index, doubledValue in doublingIterator(numbers) do
   print(index, doubledValue)
end

1 6 2 8

3 10

That pretty much covers generic for loops! Read on for some final examples!

Examples

months = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"}

revmonths = {}
    
for i, v in ipairs(months) do
   revmonths[v] = i -- Make the month name the index and the location the value
   print(v, revmonths[v])
end

January 1 -- revmonths.January = 1 February 2 -- revmonths.February = 2 March 3 April 4 May 5 -- Cinco de mayo! June 6 July 7 August 8 September 9 October 10 November 11

December 12

Here's another example returning multiple values:

string = {}
string.gfind = function(stringToSearch, Pattern, Start)
   local start = Start or 1 -- Default value is 1
   return function()
      local beginning, ending = stringToSearch:find(Pattern, start) -- Start searching at the specified location
      if beginning and ending then -- Check to make sure that the match is there
         start = ending + 1 -- Add one to the ending so the pattern will start to look after the last match
	 return beginning, ending, stringToSearch:sub(beginning, ending) -- return the 3 values
      end
   end
end

local stringToSearch = "Hello! My name is merlin1188!"

for start, finish, value in string.gfind(stringToSearch, "%a+") do
   print("The match starts at " .. start ..", finishes at " .. finish .. ", and is " .. value)
end

The match starts at 1, finishes at 5, and is Hello The match starts at 8, finishes at 9, and is My The match starts at 11, finishes at 14, and is name The match starts at 16, finishes at 17, and is is

The match starts at 19, finishes at 24, and is merlin

pairs and ipairs

pairs and ipairs are iterator functions that return table indices and their corresponding values. pairs iterates through the entire table, even if the index is non-numerical (such as "Hi"). ipairs iterates through the table at numerical index, starting at 1 until it reaches nil. Also, please note that pairs does not iterate through the table in any particular order. Here's an example of the difference:

sampleTable = {[1] = "A", [2] = 2, [3] = "B", [5] = 5, Hi = "C"}
for i, v in ipairs(sampleTable) do
   print(i, v)
end
print("That was with ipairs. This is with pairs.")
for i, v in pairs(sampleTable) do
   print(i, v)
end

1 A -- 1 2 2 -- 2 3 B -- 3 That was with ipairs. This is with pairs. 2 2 -- 2 3 B -- 3 1 A -- 1 5 5 -- 5

Hi C -- Hi