Module Iter

Specialized iteration of tables and other objects.

"pairs" methods take a single input table. "touples" methods take an arbitrary number of tables.

Module Status: Experimental 2020-10-31.

Usage:

    local Iter = require('__eradicators-library__/erlib/lua/Iter')()
    

Todo

todo-1 Find out how to make LDoc obey custom names for sections and iterators.

lua.Iter.array_pairs Functions

array_pairs(tbl, i, j) Iterates over dense, sparse or partial arrays.

lua.Iter.combinations Functions

combinations(length, arr) Iterates over all n-length combinations of the given values.

lua.Iter.dpairs Functions

dpairs([tbl[, opt]]) Deep_pairs iterates all sub-tables in a single for-loop.

lua.Iter.fpairs Functions

fpairs(tbl, f) Returns only (key → value) pairs for which f(value,key,tbl) returns true.

lua.Iter.fpairs2 Functions

fpairs2(tbl, f) Iterates the NotNil return values of a filter function over a table.

lua.Iter.ntuples Functions

ntuples(n[, tbl]) Iterates n-nested sub-tables in a single for-loop.

lua.Iter.permutations Functions

permutations([arr[, i=1[, j=#arr]]]) Iterates through all permutations that contain each value exactly once.

lua.Iter.sriapi Functions

sriapi(arr) Inverse ipairs().

lua.Iter.subsets Functions

subsets(size, arr) Produces all possible unique subsets of size n from a given superset arr.

lua.Iter.sync_tuples Functions

sync_tuples(parent, ...) Iterates multiple tables in paralell.


Todo

todo-1
Find out how to make LDoc obey custom names for sections and iterators.
  • todo -1

lua.Iter.array_pairs Functions

array_pairs(tbl, i, j)
Iterates over dense, sparse or partial arrays. Can also iterate over the array part of a MixedTable. Start and end point of the array are determind on calling, thus any changes to the array during the iteration have no effect on the interation range.

Parameters:

Returns:

    function A next-style iterator that returns (index,value) pairs when called with (tbl,last_key).

Usage:

    local my_mixed_table = {'a',[42]='u',[6]='f',test='bla'}
    
    -- By default it will find the largest key on it's own.
    for k,v in Iter.array_pairs(my_mixed_table) do print(k,v) end
    > 1 a
    > 6 f
    > 42 u
    
    -- You can enforce partial ranges. This *will* iterate the whole range
    -- even if only a few keys have values. So speficying huge numbers
    -- will just pointlessly waste CPU cycles.
    for k,v in Iter.array_pairs(my_mixed_table,6,9001) do print(k,v) end
    > 6 f
    > 42 u
    

lua.Iter.combinations Functions

combinations(length, arr)
Iterates over all n-length combinations of the given values. Each value can be in the combination multiple times.

Time complexity: Size of arr to the power of length → #arr ^ length

See also: Iter.subsets, Iter.permutations

Parameters:

Returns:

    function A stateful iterator that returns an array for each combination.

Usage:

    for arr in Iter.combinations(3,{0,1}) do print(Hydra.line(arr)) end
    > {0, 0, 0}
    > {0, 0, 1}
    > {0, 1, 0}
    > {0, 1, 1}
    > {1, 0, 0}
    > {1, 0, 1}
    > {1, 1, 0}
    > {1, 1, 1}
    

lua.Iter.dpairs Functions

dpairs([tbl[, opt]])
Deep_pairs iterates all sub-tables in a single for-loop.

This is a non-fixed-path-length fork of Iter.ntuples.

With default options every (key → value) pair is iterated exactly once. The sub-tables that are being iterated into are never output as the value of such a pair.

Parameters:

  • tbl table The input table. (optional)
  • opt (table) Options (optional).
    • include_path boolean Activates the fourth return value. (default false)
    • include_duplicates boolean When this is false and @tbl has multiple references to the same sub-table, then only the first reference to each sub-table will be iterated and all futher reference skipped. When this is true all references will be iterated normally and the fifth return value will be true for all iterations except the first. (default false)
    • ignore_recursion boolean Silently skip recursive sub-tables instead of raising an error. (default false)

Returns:

  1. NotNil key
  2. NotNil value
  3. table table This is the sub-table that contains the returned (key → value) pair.
  4. TablePath or nil path This is the full path to the value inside the input table @tbl.
  5. boolean or nil is_duplicate

Usage:

  • -- Setup the example data.
    local players = {
      yurie = {
        items = {'iron-plate', 'copper-plate'},
        ammo  = {'piercing'  , 'uranium'     },
        play_time = 9001,
        },
      tarou = {
        items = {'iron-gear' , 'copper-gear' },
        ammo  = {},
        play_time = 42,
        },
      akira = {
        items = {},
        ammo  = {'exploding' , 'magic'       },
        play_time = 7,
        },
      }
    
    -- Introduce some duplicate table references.
    players.michiru           = players.tarou
    players.akira.ammo['ref'] = players.yurie.ammo
    
    -- And an easy to read format.
    local function format_row(key, value, path, is_duplicate)
      return ('%-28s %-10s %-13s %-5s')
        :format(Hydra.line(path), key, value, is_duplicate and '(duplicate)' or '')
      end
    
  • -- Example 1: Path. (Also notice that duplicates are ignored by default.)
    
      for key, value, tbl, path in
        Iter.dpairs(players, {include_path = true}) do
        print(format_row(key, value, path))
        end
    
    --[path]                       [key]      [value]
    > {"michiru", "items", 1}      1          iron-gear
    > {"michiru", "items", 2}      2          copper-gear
    > {"michiru", "play_time"}     play_time  42
    > {"akira", "ammo", 1}         1          exploding
    > {"akira", "ammo", 2}         2          magic
    > {"akira", "play_time"}       play_time  7
    > {"yurie", "ammo", 1}         1          piercing
    > {"yurie", "ammo", 2}         2          uranium
    > {"yurie", "items", 1}        1          iron-plate
    > {"yurie", "items", 2}        2          copper-plate
    > {"yurie", "play_time"}       play_time  9001
    
  • -- Example 2: Duplicates.
    
    for key, value, tbl, path, is_duplicate in
      Iter.dpairs(players, {include_path = true, include_duplicates=true}) do
      print(format_row(key, value, path, is_duplicate))
      end
    
    --[path]                       [key]      [value]
    > {"michiru", "items", 1}      1          iron-gear
    > {"michiru", "items", 2}      2          copper-gear
    > {"michiru", "play_time"}     play_time  42
    > {"akira", "ammo", 1}         1          exploding
    > {"akira", "ammo", 2}         2          magic
    > {"akira", "ammo", "ref", 1}  1          piercing      -- notice pairs-based
    > {"akira", "ammo", "ref", 2}  2          uranium       -- random order
    > {"akira", "play_time"}       play_time  7
    > {"yurie", "ammo", 1}         1          piercing      (duplicate)
    > {"yurie", "ammo", 2}         2          uranium       (duplicate)
    > {"yurie", "items", 1}        1          iron-plate
    > {"yurie", "items", 2}        2          copper-plate
    > {"yurie", "play_time"}       play_time  9001
    > {"tarou", "items", 1}        1          iron-gear     (duplicate)
    > {"tarou", "items", 2}        2          copper-gear   (duplicate)
    > {"tarou", "play_time"}       play_time  42            (duplicate)
    
    
  • -- Example 3: Recursion.
    
    -- Let's introduce a loop...
    players.tarou.loop = players
    
    -- and try the same command as in Example 2...
    for key, value, tbl, path, is_duplicate in
      Iter.dpairs(players, {include_path = true, include_duplicates=true}) do
      print(format_row(key, value, path, is_duplicate))
      end
    
    > Error!
    > Table recursion detected but not allowed.
    > path: {"michiru", "loop"}
    
    -- Notice that "michiru" and "tarou" reference the same sub-table.
    -- The error message reports whichever path it found first.
    
    -- Now let't try again with irgnore mode...
    for key, value, tbl, path, is_duplicate in
      Iter.dpairs(players, {
        include_path = true, include_duplicates=true, ignore_recursion = true
        })
      do
      print(format_row(key, value, path, is_duplicate))
      end
    
    > --[[This produces output identical to Example 2.]]
    
    

lua.Iter.fpairs Functions

fpairs(tbl, f)
Returns only (key → value) pairs for which f(value,key,tbl) returns true. Other values in the table are simply skipped during iteration.

Parameters:

  • tbl table The table to be iterated.
  • f function The filter function f(value,key,table).

Returns:

    A stateless iterator function.

Usage:

    -- For example if you've got stored LuaEntity references
    script.on_event(defines.events.on_built_entity,function(event)
       if event.entity.name == 'MyEntity' then
         global.MyEntityData[event.entity.unit_number] = {entity=event.entity}
         end
       end)
    
    -- And want to remove the invalid ones. (Ignores key+tbl arguments)
    local filter = function(data,_,_) return not data.entity.valid end
    
    for unit_number,_ in pairs(global.MyEntityData,filter) do
       global.MyEntityData[unit_number] = nil
       end
    

lua.Iter.fpairs2 Functions

fpairs2(tbl, f)
Iterates the NotNil return values of a filter function over a table.

Parameters:

Returns:

    function A stateful iterator function. For each call of the iterator it returns all return values of the next call of 'f(value,key,tbl)' that returns at least one value. The iterator terminates after f has been called on all elemetnts of tbl.

lua.Iter.ntuples Functions

ntuples(n[, tbl])
Iterates n-nested sub-tables in a single for-loop.

Returns every possible path of length n-1 and its value. This might lead to unexpected results when the input table is recursive or has multiple references to the same sub-table.
See also Iter.dpairs.

Internally uses pairs() to get each sub-table's __pairs metamethod or next().
See also Metatables and Metamethods.

Every sub-table must be at least of depth n-1 or the loop will crash. Completely empty sub-tables are the only exception and will instead be ignored.

Parameters:

  • n NaturalNumber The length of the desired tuple. The returned tuple is of the form ("Key 1", "Key 2", ..., "Key n-1", "Value"), thus the value is included in the length of the touple.
  • tbl table The parent table to iterate into. (optional)

Returns:

    function There are three cases:

    When tbl == nil returns Filter.SKIP.
    When n <= 2 returns the three values returned by pairs(tbl).
    When n > 2 returns a stateful ntuples-iterator function and nothing else.

Usage:

    local players = {
      yurie = {
        items = {'iron-plate', 'copper-plate'},
        ammo  = {'piercing'  , 'uranium'     },
        },
      tarou = {
        items = {'iron-gear' , 'copper-gear' },
        ammo  = {}, -- empty table is ignored because it's not deep enough.
        },
      akira = {
        items = {},
        ammo  = {'exploding' , 'magic'       },
        },
      }
    
    for nickname, type, item_index, item_name in Iter.ntuples(4, players) do
      print(nickname, type, item_index, item_name)
      end
    
    > yurie items 1 iron-plate
    > yurie items 2 copper-plate
    > yurie ammo  1 piercing
    > yurie ammo  2 uranium
    > tarou items 1 iron-gear
    > tarou items 2 copper-gear
    > akira ammo  1 exploding
    > akira ammo  2 magic
    

lua.Iter.permutations Functions

permutations([arr[, i=1[, j=#arr]]])
Iterates through all permutations that contain each value exactly once. A permutation is a list in which only the order of elements changes.

Time complexity: Factorial of size of arr → #arr!

See also: Iter.combinations, Iter.subsets

Parameters:

Returns:

    function A stateful iterator that returns an array for each permutation.

Usage:

    for arr in Iter.permutations({1,2,3,4,5},1,3) do print(Hydra.line(arr)) end
    > {1, 2, 3}
    > {1, 3, 2}
    > {3, 1, 2}
    > {3, 2, 1}
    > {2, 3, 1}
    > {2, 1, 3}
    

lua.Iter.sriapi Functions

sriapi(arr)
Inverse ipairs().

Parameters:

Returns:

    function f() A stateful iterator. When the iterator is called f() it returns (value, index) of the next entry in the array. Note: this means that the order of the return values is also inversed compared to normal ipairs().

    The __ipairs methamethod of arr is ignored by this iterator.

Usage:

    for v,i in sriapi({'a','b','c','d','e'}) do print(('i=%s, v=%s'):format(i,v)) end
    > i=5, v=e
    > i=4, v=d
    > i=3, v=c
    > i=2, v=b
    > i=1, v=a
    

lua.Iter.subsets Functions

subsets(size, arr)
Produces all possible unique subsets of size n from a given superset arr. This means that it is guaranteed that for each possible combination of unique elements exactly one permutation will occur.

Time complexity: It depends *cough*.

Note: Despite the name sub-"set" all in- and outputs use array format for better performance.

See also: Iter.combinations, Iter.permutations

Parameters:

  • size NaturalNumber The exact size of each subset.
  • arr array An array representing all elements of the source set.

Returns:

    function A stateful iterator that returns an array for each subset.

Usage:

  • -- A set with n elements only has one subset of length n.
    for s in Iter.subsets(3,{1,2,3}) do print(Hydra.line(s)) end
    > {1, 2, 3}
    
  • for s in Iter.subsets(3,{1,2,3,4,5}) do print(Hydra.line(s)) end
    > {1, 2, 3}
    > {1, 2, 4}
    > {1, 2, 5}
    > {1, 3, 4}
    > {1, 3, 5}
    > {1, 4, 5}
    > {2, 3, 4}
    > {2, 3, 5}
    > {2, 4, 5}
    > {3, 4, 5}
    

lua.Iter.sync_tuples Functions

sync_tuples(parent, ...)
Iterates multiple tables in paralell.

Note: Standard next rules apply regarding in-loop manipulation of the parent table.

Note: If the parents has a __pairs metamethod its resulting keys are used for all child tables.

Parameters:

  • parent table This determines which keys are iterated.
  • ... table or nil Additional tables to be iterated.

Returns:

    k,v1,v2,v3,... Each iteration return the key and the value for each table in the order the tables were given.

Usage:

    -- Keys not in the parent table won't be iterated.
    local par = {nil, 'b', 'c', 'd', false, ['x'] = 'f'}
    -- Other tables nil keys will just return nil.
    local t1  = {'A', 'B', 'C', nil, 'E', ['x'] = 'F'}
    local t2  = {nil, nil,  3 ,  4 ,  5 , ['x'] =  6 }
    -- Empty arguments are assumed to be empty tables.
    local t3  =  nil
    
    for k,vp,v1,v2,v3 in Iter.sync_tuples(par,t1,t2,t3) do
      print(k,':',vp,v1,v2,v3)
      end
    
    > 2 : b     B   nil nil
    > 3 : c     C   3   nil
    > 4 : d     nil 4   nil
    > 5 : false E   5   nil
    > x : f     F   6   nil
    
    
generated by LDoc 1.4.6 Last updated 2021-09-10 19:51:19