GMLscripts.com

Discuss and collaborate on GML scripts
Invert

You are not logged in.

#1 2021-06-16 07:08:37

maras
Member
Registered: 2021-04-25
Posts: 22
Website

foreach

Expand/// 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:

Expandvar 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)

Offline

#2 2021-06-17 10:27:23

xot
Administrator
Registered: 2007-08-18
Posts: 1,238

Re: foreach

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.

Expandds_type_map
ds_type_list
ds_type_stack
ds_type_grid
ds_type_queue
ds_type_priority

Abusing forum power since 1986.

Offline

#3 2021-06-17 10:57:58

maras
Member
Registered: 2021-04-25
Posts: 22
Website

Re: foreach

Already tried that but ds_exists does not check it correctly
When I use

Expandds_exists(list, ds_type_list)

it returns true
but when I use

Expandds_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)

Offline

#4 2021-06-17 12:44:05

xot
Administrator
Registered: 2007-08-18
Posts: 1,238

Re: foreach

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.

Expandforeach(list, ds_type_list, some_function);
Expand...		
		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

#5 2021-06-17 16:11:18

maras
Member
Registered: 2021-04-25
Posts: 22
Website

Re: foreach

Ohh ok I get it
And for array you can also use ds_type_list and then check it with is_array()

Offline

#6 2021-06-17 17:23:37

xot
Administrator
Registered: 2007-08-18
Posts: 1,238

Re: foreach

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.

Expand// 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

#7 2021-06-20 18:16:46

maras
Member
Registered: 2021-04-25
Posts: 22
Website

Re: foreach

Found a way to get the type
it's pretty heavy tho

Expandfunction ds_get_type(ds) {
	
	if is_array(ds) return -1;
	
	try {
		if ds_list_size(ds) {}
		return ds_type_list;
	} catch(e) {
		try {
			if ds_map_size(ds) {}
			return ds_type_map;
		} catch(e) {
			try {
				if ds_grid_height(ds) {}
				return ds_type_grid;
			} catch(e) {
				return undefined;
			}
		}
	}
}

Last edited by maras (2021-06-20 18:26:42)

Offline

#8 2021-06-20 22:16:36

xot
Administrator
Registered: 2007-08-18
Posts: 1,238

Re: foreach

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.

Expandgrid = 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

#9 2021-06-21 07:26:38

maras
Member
Registered: 2021-04-25
Posts: 22
Website

Re: foreach

f hell...

Offline

Board footer

Powered by FluxBB