Initialize an Array in One Line?

N

NQShabazz

Guest
In GML, is it possible to cleanly declare and initialize an array in one line?
Something like:
Code:
var myArray = {0, "lol", 244, c_white};
?

Although on second thought, I can always make a script for this, I'd like to know if GML has anything built-in.
 
S

Salvakiya

Guest
yes you can.

make a script called array.
Code:
///array(*args);
var arr;
for (var i=0;i<argument_count;i+=1)
{
    arr[i] = argument[i];
}
return arr;
var my_array = array(0, "lol", 244, c_white);

TADAAA!!!!

there are many work around's for GM's shortcomings
 
I use a string parser for declaring most of my arrays (unless I need to squeeze the program for speed), there's this one:

Code:
/// string_split_ext(string, *delimiter) = array;

var str = argument[0],
  delim = "|";

var arr = 0,
  c1 = 0,
  p1 = 0;

if (str == "")
{
  return undefined;
}

if (argument_count >= 2)
{
  delim = argument[1];
}

do
{
  var temp = "";
  
  p1 = string_pos(delim, str);
  
  if (p1 == 0)
  {
  temp = str;
  }
  else
  {
  temp = string_copy(str, 1, p1 - 1);
  
  str = string_delete(str, 1, p1);
  }
  
  if (string_char_at(temp, 1) == "$")
  {
  temp = string_delete(temp, 1, 1);
  }
  else
  {
  temp = real(temp);
  }
  
  arr[c1++] = temp;
} until (p1 == 0)

return (arr);
... Which can be used like this:

Code:
my_array = string_split_ext("$Hello World!|999|$stainedofmind|0|1|2|3|4|$$5.99");
... Where it will return any value starting with '$' as a string, otherwise it will be a real. The last value in the example will also be a string equal to '$5.99'. The problem with this if course is string breaking to add variable values, resource IDs, and running scripts and equations, so I typically use the above in conjunction with a simple script I call 'strf', as below:

Code:
/// strf(str, arguments) = new_str;

var str = argument[0];

var c1 = 1;

repeat (argument_count - 1)
{
  str = string_replace_all(str, "$" + string(c1 - 1), string(argument[c1]));
  
  c1++;
}

return (str);
... Which simply replaces all instances of '$x' with the matching value in the arguments, like this:

Code:
player_name = "stainedofmind";
greeting = strf("Hello, $0!", player_name);
... So a combination would be:

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$5.99", player_name));
... Of course, careful inspection of the code would show that the last entry could be modified if 6 or more arguments are given to strf. My solution would be to just provide it as an argument itself, like this (just pretend I actually use the extra arguments...):

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$6", player_name, 0, 1, 2, 3, 4, "$5.99", "Butts"));
.... Anyway, enough ranting. Use these scripts if you like. One of these days I'll probably just make a combined version of these scripts if I keep using them as much as I have been lately. Maybe even with escape characters.
 
S

Salvakiya

Guest
I use a string parser for declaring most of my arrays (unless I need to squeeze the program for speed), there's this one:

Code:
/// string_split_ext(string, *delimiter) = array;

var str = argument[0],
  delim = "|";

var arr = 0,
  c1 = 0,
  p1 = 0;

if (str == "")
{
  return undefined;
}

if (argument_count >= 2)
{
  delim = argument[1];
}

do
{
  var temp = "";

  p1 = string_pos(delim, str);

  if (p1 == 0)
  {
  temp = str;
  }
  else
  {
  temp = string_copy(str, 1, p1 - 1);

  str = string_delete(str, 1, p1);
  }

  if (string_char_at(temp, 1) == "$")
  {
  temp = string_delete(temp, 1, 1);
  }
  else
  {
  temp = real(temp);
  }

  arr[c1++] = temp;
} until (p1 == 0)

return (arr);
... Which can be used like this:

Code:
my_array = string_split_ext("$Hello World!|999|$stainedofmind|0|1|2|3|4|$$5.99");
... Where it will return any value starting with '$' as a string, otherwise it will be a real. The last value in the example will also be a string equal to '$5.99'. The problem with this if course is string breaking to add variable values, resource IDs, and running scripts and equations, so I typically use the above in conjunction with a simple script I call 'strf', as below:

Code:
/// strf(str, arguments) = new_str;

var str = argument[0];

var c1 = 1;

repeat (argument_count - 1)
{
  str = string_replace_all(str, "$" + string(c1 - 1), string(argument[c1]));

  c1++;
}

return (str);
... Which simply replaces all instances of '$x' with the matching value in the arguments, like this:

Code:
player_name = "stainedofmind";
greeting = strf("Hello, $0!", player_name);
... So a combination would be:

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$5.99", player_name));
... Of course, careful inspection of the code would show that the last entry could be modified if 6 or more arguments are given to strf. My solution would be to just provide it as an argument itself, like this (just pretend I actually use the extra arguments...):

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$6", player_name, 0, 1, 2, 3, 4, "$5.99", "Butts"));
.... Anyway, enough ranting. Use these scripts if you like. One of these days I'll probably just make a combined version of these scripts if I keep using them as much as I have been lately. Maybe even with escape characters.
That may work. It is far more expensive than the array script I posted. If you plan on using alot of arrays you should not parse a string each time as he says. I think you both would benefit from the array script =P

EDIT; it is also good to note that 1d arrays are the same as 2d arrays in GMS. A "1d" array just defaults the second dimension to 0.
 
N

NQShabazz

Guest
I use a string parser for declaring most of my arrays (unless I need to squeeze the program for speed), there's this one:

Code:
/// string_split_ext(string, *delimiter) = array;

var str = argument[0],
  delim = "|";

var arr = 0,
  c1 = 0,
  p1 = 0;

if (str == "")
{
  return undefined;
}

if (argument_count >= 2)
{
  delim = argument[1];
}

do
{
  var temp = "";

  p1 = string_pos(delim, str);

  if (p1 == 0)
  {
  temp = str;
  }
  else
  {
  temp = string_copy(str, 1, p1 - 1);

  str = string_delete(str, 1, p1);
  }

  if (string_char_at(temp, 1) == "$")
  {
  temp = string_delete(temp, 1, 1);
  }
  else
  {
  temp = real(temp);
  }

  arr[c1++] = temp;
} until (p1 == 0)

return (arr);
... Which can be used like this:

Code:
my_array = string_split_ext("$Hello World!|999|$stainedofmind|0|1|2|3|4|$$5.99");
... Where it will return any value starting with '$' as a string, otherwise it will be a real. The last value in the example will also be a string equal to '$5.99'. The problem with this if course is string breaking to add variable values, resource IDs, and running scripts and equations, so I typically use the above in conjunction with a simple script I call 'strf', as below:

Code:
/// strf(str, arguments) = new_str;

var str = argument[0];

var c1 = 1;

repeat (argument_count - 1)
{
  str = string_replace_all(str, "$" + string(c1 - 1), string(argument[c1]));

  c1++;
}

return (str);
... Which simply replaces all instances of '$x' with the matching value in the arguments, like this:

Code:
player_name = "stainedofmind";
greeting = strf("Hello, $0!", player_name);
... So a combination would be:

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$5.99", player_name));
... Of course, careful inspection of the code would show that the last entry could be modified if 6 or more arguments are given to strf. My solution would be to just provide it as an argument itself, like this (just pretend I actually use the extra arguments...):

Code:
player_name = "stainedofmind";
my_array = string_split_ext(strf("$Hello, $0!|999|$$0|0|1|2|3|4|$$6", player_name, 0, 1, 2, 3, 4, "$5.99", "Butts"));
.... Anyway, enough ranting. Use these scripts if you like. One of these days I'll probably just make a combined version of these scripts if I keep using them as much as I have been lately. Maybe even with escape characters.
That's a lot to do to make an array 0_0. Still, that's pretty good for maybe reading files at the start of the program
 
E

elementbound

Guest
To add to Yal's answer: It's better to start at the end of the array, because that way GMS will reserve the memory needed for the whole array in one go. If you were to start from the beginning, the array would have to be resized each iteration to grow.
 
I am aware of the overhead in the method I posted, and I do have a series of scripts to work directly with arrays, but those are limited to the 16 arguments of a script, where the one I posted (save for the strf portion) is limited only by the maximum string length... And deliminator character of course!
 
S

Salvakiya

Guest
I am aware of the overhead in the method I posted, and I do have a series of scripts to work directly with arrays, but those are limited to the 16 arguments of a script, where the one I posted (save for the strf portion) is limited only by the maximum string length... And deliminator character of course!
If I were to do that though I would just write my values in Json and make a map to array script. then you can just used json_decode to decode the json data.

Edit:
Freddy Jones fixed this jarray script
Code:
///jarray(json_list)
var map = json_decode(argument0);
// if the json could not be parsed json_decode returns -1
if( map == -1 ){ show_error("Json could not be read.", false);}
// if it was a list, the list is found in "default
var list = ds_map_find_value(map, "default");
var len = ds_list_size(list);
for (var i = 0, arr; i < len; i ++ ){
    arr[i] = list[|i];
}
ds_map_destroy(map);
ds_list_destroy(list);
return arr;
usage would be jarray("[1,2,3,'a','b','c']")
 
Last edited:
If I were to do that though I would just write my values in Json and make a map to array script. then you can just used json_decode to decode the json data.

Edit:
Code:
///jarray(string json list)
var arr,i,list,str;
str = argument[0]
list = json_decode(str);
for (i=ds_list_size(list)-1; i>=0; i--){
    arr[i] = list[|i];
};
ds_list_destroy(list)
return arr;
usage would be jarray("[1,2,3,'a','b','c']")
While I really need to jump on the JSON bandwagon eventually, my way is still faster to type for me, plus JSON converts to data structures and not arrays.
 
S

Salvakiya

Guest
While I really need to jump on the JSON bandwagon eventually, my way is still faster to type for me, plus JSON converts to data structures and not arrays.
if you try the code snippet I put with my post you will see it returns an array. all you have to do is pass it a string like so:
thearray = jarray("[1,2,3,4,5,'a','b','c',3,4,5,6,34,5,3,46,34,5,345,34,6,6]");

if you need any real values in there you can also do that as well
thearray = jarray("[1,2,3,"+string(score)+",values,blah]")


this is not limited to a delimiter and it is not limited to 16 values. the code I pasted does get a ds from the json string but turns it into an array. It is far easier to use. for any array which has 16 or less values I would use Yal's version... any more I would use this jarray version... and when I am optimising my game I would refactor it out completely.
 
Oh, missed the array part. My bad. Of course, I wouldn't consider using the scripts I posted for performance heavy applications. I mostly just use them for once off, low impact areas. If I need arrays in high performance areas, I'd just code them manually. I wouldn't say yours is any easier to use, per say, simpler maybe, and yes, not limited to the delimiter (there's a bad pun in there somewhere). Just my preferred method is all.
 

Freddy Jones

Your Main Detective
I'd recommend not doing it at all, honestly. The time it will save you to write, won't save you the time it takes to debug and read. You'll also find that using these "string_to_array" functions will get pretty cumbersome when you want to insert a variable. If you're trying to find a specific index it might take you more time to look through the string instead of just looking for an index number that's already been pre-set. That's my two cents.

Also, before using Salvakiya's code, there's a small problem with his usage of json_decode. It always returns a map, not a list, but can be used to get/parse lists nonetheless.
 
S

Salvakiya

Guest
I'd recommend not doing it at all, honestly. The time it will save you to write, won't save you the time it takes to debug and read. You'll also find that using these "string_to_array" functions will get pretty cumbersome when you want to insert a variable. If you're trying to find a specific index it might take you more time to look through the string instead of just looking for an index number that's already been pre-set. That's my two cents.

Also, before using Salvakiya's code, there's a small problem with his usage of json_decode. It always returns a map, not a list, but can be used to get/parse lists nonetheless.
it in fact does not always return a map. If the string starts with [ it returns a list... if its a { it returns a map. Let me know if I am wrong but you cant ds_list_destroy on a map. at least not in my tests.
 

Freddy Jones

Your Main Detective
it in fact does not always return a map. If the string starts with [ it returns a list... if its a { it returns a map. Let me know if I am wrong but you cant ds_list_destroy on a map. at least not in my tests.
I would go with what the manual says. It says it will create a ds_map, and then for any lists found in the json it will make a list for on the inside. If you haven't made any lists or maps prior to calling the json function, it will seem that it returned a list, but in fact it will be chance that both the map and the list are of the same index (0 in this case).

Therefor, it is best to stick with the example provided in the docs. If this is not true, then it is undocumented behaviour.
 
S

Salvakiya

Guest
I would go with what the manual says. It says it will create a ds_map, and then for any lists found in the json it will make a list for on the inside. If you haven't made any lists or maps prior to calling the json function, it will seem that it returned a list, but in fact it will be chance that both the map and the list are of the same index (0 in this case).

Therefor, it is best to stick with the example provided in the docs. If this is not true, then it is undocumented behaviour.
I can confirm after further testing it does in fact return a map as you stated... silly me =P. one should use Freddy's version if they are to use it.
 
Top