You are not logged in.
Pages: 1
/// foreach(data, type, f_each)
//
// returns nothing
//
// data array / ds_list / ds_map / ds_grid
// type what type of data is entering, ds_type
// f_each what to do with each value, function
//
// type:
// for array / ds_list: ds_type_list
// for ds_map: ds_type_map
// for ds_grid: ds_type_grid
//
// f_each:
// function(data, index, val)
//
// returns undefined or true
//
// data returned data so it's accessible inside of the inner function
// index returned current data index/key
// array: position, real
// ds_list: position, real
// ds_map: key, string
// ds_grid: positions, array[x, y]
//
// val returned current data value
//
// to break the foreach loop simply return true inside of the inner function
//
/// GMLscripts.com/license
function foreach(data, type, f_each) {
switch(type) {
case ds_type_list:
if is_array(data){
var len = array_length(data);
for(var i = 0; i < len; i++) {
if f_each(data, i, data[i]) break;
}
}
else {
var len = ds_list_size(data);
for(var i = 0; i < len; i++) {
if f_each(data, i, data[| i]) break;
}
}
break;
case ds_type_map:
for(var key = ds_map_find_first(data); !is_undefined(key); key = ds_map_find_next(data, key)) {
if f_each(data, key, data[? key]) break;
}
break;
case ds_type_grid:
var w = ds_grid_width(data);
var h = ds_grid_height(data);
for(var xx = 0; xx < w; xx++) {
for(var yy = 0; yy < h; yy++) {
if f_each(data, [xx, yy], data[# xx, yy]) break;
}
}
break;
}
}
Example code:
var list = ds_list_create();
ds_list_add(list, "one");
ds_list_add(list, "two");
ds_list_add(list, "three");
foreach(list, ds_type_list, function(d, i, v) {
if i == 2 return true; // break
show_debug_message(string(i)+": "+string(v));
});
// *console*
// 0: one
// 1: two
Last edited by maras (2021-06-17 16:30:11)
I'm on the official GM discord > maras_cz
Offline
Thanks. One change I would make straight away is using the GameMaker constants instead of strings to identify the data structure types. In the future, this should not be necessary but for now, identification is needed. I also might extend this for all data structure types.
ds_type_map
ds_type_list
ds_type_stack
ds_type_grid
ds_type_queue
ds_type_priority
Abusing forum power since 1986.
Offline
Already tried that but ds_exists does not check it correctly
When I use
ds_exists(list, ds_type_list)
it returns true
but when I use
ds_exists(list, ds_type_map)
it also returns true
https://www.reddit.com/r/gamemaker/comm … _and_data/
Last edited by maras (2021-06-17 10:59:07)
I'm on the official GM discord > maras_cz
Offline
Not like that. I would use case statements like you already do but with constants instead of an arbitrary string. This is faster and uses less memory (admittedly tiny optimizations) and it is also self-documenting and easier to remember.
foreach(list, ds_type_list, some_function);
...
case ds_type_list:
var len = ds_list_size(data);
for(var i = 0; i < len; i++) {
if f_each(data, i, data[| i]) break;
}
break;
...
As you've found, right now a data structure reference is simply a global index value of real
type and not a resource or reference with its own type (or value from which a type can be derived). Because of the way GameMaker generates the values, there can be collisions, eg. the first list and the first grid will both have the same index value. One day you'll be able to detect them properly, but for now ds_exists()
can only tell if an index is valid and cannot tell indices of different data structure types apart in an implicit way.
Abusing forum power since 1986.
Offline
Oh, whoops. I missed the array. Hmmm, that's unfortunate. Checking if it is an array first might be the way to go. If it is, ignore the given type. That needs some testing because GameMaker always finds a way to make things weirdly difficult. Such a shame Mark Overmars didn't design the data structure system with unique indices mapped to types.
I'm adding this here for my notes. Passing 0
(zero) could mean array
but that shouldn't be relied on since these constants could conceivably change.
// data structure constant values
// ds_type_map == 1
// ds_type_list == 2
// ds_type_stack == 3
// ds_type_queue == 4
// ds_type_grid == 5
// ds_type_priority == 6
Also considered rearranging the parameters, making type
the final parameter and optional, defaulting to array
if not given but I'm not sure I like it aesthetically.
Abusing forum power since 1986.
Offline
That doesn't really work. If you have grid and list ids that are equal, your grid would identify as a list. That misidentification could lead to all kinds of problems.
grid = ds_grid_create(5,5);
list = ds_list_create();
switch (ds_get_type(grid)) {
case ds_type_grid:
show_debug_message("grid");
break;
case ds_type_list:
show_debug_message("list");
break;
case ds_type_map:
show_debug_message("map");
break;
}
Abusing forum power since 1986.
Offline
Pages: 1