You are not logged in.
Pages: 1
A stackable foreach loop for arrays, lists, maps, structs, grids, strings and number ranges.
This foreach was made using macros so you don't have to pass variables like arguments. You can access them inside of the loop directly.
Reserved keywords: Foreach, Feach, inAarray, inInvArray inList, inInvList, inMap, inStruct, inGrid, inInvGrid, inString, inInvString, inRange, Loop + a global variable FEDATA.
[v2.0.3] Auto init
+ No need for manual initialization anymore
+ Also realized I accidentally placed the loop stuff inside the init function (but it worked so... eh)
[v2.0.2] Speeed
+ Up to 3x faster than the previous version
+ Syntax update - the returned value is now an actual variable instead of being stored in a global struct
Syntax
Feach <var> inData <data> Run
<var> - a variable to use (will overwrite it if already exists)
inData - datatype
<data> - data specified with inData
You can use break and continue
The keyword Loop contains the current loop data like the current index (Loop.i), the current key (Loop.key) or the map function (Loop.map(x))
Note: Feach is just shortened Foreach and you can use the one you prefer
Just in case I ever forget to update it on this forum:
https://github.com/mh-cz/GameMaker-Foreach
/// foreach v2.0.3
//
// Feach <var> inData <data> Run
//
// <var> - a variable to use (will overwrite it if already exists)
// inData - datatype
// <data> - data specified with inData
//
/// GMLscripts.com/license
global.FEDATA = [[], -1];
function _FeArray_(inv, data) constructor {
self.data = data;
self.i = -1;
self.len = array_length(data);
self.step = 1;
if inv {
i = len;
step = -step;
}
static map = function(v) {
data[@ i] = v;
}
static next = function() {
i += step;
return i < len and i > -1;
}
static get = function() {
return data[i];
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeList_(inv, data) constructor {
self.data = data;
self.i = -1;
self.len = ds_list_size(data);
self.step = 1;
if inv {
i = len;
step = -step;
}
static map = function(v) {
data[| i] = v;
}
static next = function() {
i += step;
return i < len and i > -1;
}
static get = function() {
return data[| i];
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeMap_(data) constructor {
self.data = data;
self.i = -1;
self.key = "";
self.keys = ds_map_keys_to_array(data);
self.len = array_length(keys);
self.step = 1;
static map = function(v) {
data[? key] = v;
}
static next = function() {
i += step;
return i < len;
}
static get = function() {
key = keys[i];
return data[? key];
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeStruct_(data) constructor {
self.data = data;
self.i = -1;
self.key = "";
self.keys = variable_struct_get_names(data);
self.len = array_length(keys);
self.step = 1;
static map = function(v) {
data[$ key] = v;
}
static next = function() {
i += step;
return i < len;
}
static get = function() {
key = keys[i];
return data[$ key];
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeGrid_(inv, data) constructor {
self.data = data;
self.xpos = 0;
self.ypos = 0;
self.w = ds_grid_width(data);
self.h = ds_grid_height(data);
self.i = -1;
self.len = w * h;
self.step = 1;
if inv {
i = len;
step = -step;
}
static map = function(v) {
data[# xpos, ypos] = v;
}
static next = function() {
i += step;
return i < len and i > -1;
}
static get = function() {
xpos = i mod w;
ypos = i div h;
return data[# xpos, ypos];
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeRange_() constructor {
self.from = 0;
self.to = 1;
self.step = 1;
self.i = 0;
switch(argument_count) {
case 1:
to = argument0;
break;
case 2:
from = argument0 - step;
to = argument1;
i = from;
break;
case 3:
step = abs(argument2);
from = argument0 - step;
to = argument1;
i = from;
break;
}
static map = function(v) {
data[# xpos, ypos] = v;
}
static next = function() {
i += step;
return (from < to and i < to) or (from > to and i > to);
}
static get = function() {
return i;
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
function _FeString_(inv, data) constructor {
self.data = data;
self.i = -1;
self.len = string_length(data);
self.step = 1;
if inv {
i = len;
step = -step;
}
static next = function() {
i += step;
return i < len and i > -1;
}
static get = function() {
return string_char_at(data, i+1);
}
static yeet = function() {
array_pop(global.FEDATA[0]);
var l = array_length(global.FEDATA[0]);
if l != 0 Loop = global.FEDATA[0][l-1];
}
}
#macro Loop global.FEDATA[1]
#macro Foreach \
for(var _DataLoadeD_ = false, _CanLooP_ = false; true; { \
if _DataLoadeD_ { _CanLooP_ = true; if !Loop.next() { Loop.yeet(); break; } var
#macro Feach \
for(var _DataLoadeD_ = false, _CanLooP_ = false; true; { \
if _DataLoadeD_ { _CanLooP_ = true; if !Loop.next() { Loop.yeet(); break; } var
#macro Run \
); array_push(global.FEDATA[0], Loop); } \
}) if _CanLooP_
#macro inArray \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeArray_(false,
#macro inInvArray \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeArray_(true,
#macro inList \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeList_(false,
#macro inInvList \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeList_(true,
#macro inMap \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeMap_(
#macro inStruct \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeStruct_(
#macro inGrid \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeGrid_(false,
#macro inInvGrid \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeGrid_(true,
#macro inRange \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeRange_(
#macro inString \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeString_(false,
#macro inInvString \
= Loop.get(); } else { _DataLoadeD_ = true; Loop = new _FeString_(true,
Examples
Array - return value
var arr = [1, 2, 3, 4];
Feach v inArray arr Run
show_debug_message(v);
> 1
> 2
> 3
> 4
Array - return index and value
var arr = ["a","b","c","d"];
Feach v inArray arr Run
show_debug_message(string(Loop.i) + ", " + string(v));
> 0, a
> 1, b
> 2, c
> 3, d
Array - simple map
var arr = [1, 2, 3, 4];
var multip = 10;
Feach num inArray arr Run
Loop.map(num * multip);
The array now contains: [10, 20, 30, 40]
List - change some values inside
var some_values = ds_list_create();
some_values[| 0] = 1;
some_values[| 1] = 2;
some_values[| 2] = 3;
some_values[| 3] = 4;
var add = 10;
Feach v inList some_values Run {
if Loop.i == 1 Loop.map(-v);
else if Loop.i == 2 Loop.map(sqr(v));
else if Loop.i == 3 Loop.map(v + add);
}
// now return them
Feach v inList some_values Run
show_debug_message(v);
> 1
> -2
> 9
> 14
Grid - store cell coordinate into each cell
var grd = ds_grid_create(3,3);
Feach v inGrid grd Run
Loop.map([Loop.xpos, Loop.ypos]);
The grid now contains:
[0,0] [1,0] [2,0]
[0,1] [1,1] [2,1]
[0,2] [1,2] [2,2]
Struct
var animals = {
dogs: 10,
cats: 4,
rats: 9,
cows: 7,
goats: 2,
};
Feach anim_count inStruct animals Run {
if anim_count < 0 Loop.map(0);
if Loop.key == "cats" Loop.map(100);
}
Number ranges (returned values written in a single line cuz it's long)
Feach v inRange 5 Run
show_debug_message(v);
> 0, 1, 2, 3, 4
Feach v inRange 2, 5 Run
show_debug_message(v);
> 2, 3, 4
Feach v inRange 2, -2 Run
show_debug_message(v);
> 2, 1, 0, -1
Feach v inRange 2, -2, 0.5 Run
show_debug_message(v);
> 2, 1.5, 1, 0.5, 0, -0.5, -1, -1.5
Stackable like regular for loop
Feach v1 inArray some_arr Run
Feach v2 inStruct v1 Run
Feach v3 inRange -v2, v2 Run
do_something(v1, v2, v3);
One-liner possibilities
if !is_array(some_data) {
...
}
else Feach v inArray some_data Run {
...
}
Last edited by maras (2022-05-17 11:50:33)
I'm on the official GM discord > maras#5104
Offline
Whoa! I'll have to think about this.
Abusing forum power since 1986.
Offline
Pages: 1