Array: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Added example for pointers)
m (Add param example)
(22 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{warning | From Arma 3  v1.55.133789 arrays are limited to maximum of '''9,999,999''' (sometimes 10,000,000) elements}}
{{SideTOC}}
'''Array'''s are lists of items of varying [[:Category:Types|variable types]]. Arrays can be both single-dimension and multi-dimensional.
An '''Array''' is a list of items of varying [[:Category:Types|variable types]]. Different types can coexist within the same array.
An Array can either be one-dimensional or multi-dimensional.
{{Warning | Since {{arma3}} v1.55.133789 arrays are limited to maximum of '''9,999,999''' (sometimes 10,000,000) elements}}




== Working with arrays ==
== Working with arrays ==
=== Creating (declaring) arrays ===
Declaration of an array refers to when an array is created in a script. An array can either be declared as empty, or it can be declared with already created elements. When an array is declared as empty as in the example below, it has no elements, and has an element count of 0. When referring to items within an array, the order runs from left-to-right, beginning with the number 0 (0,1,2,3).


<code>// Example of an empty array
=== Array properties ===
_myVariable = [];
_count = [[count]] _myVariable; // Output: 0


// Correct syntax
An array variable is a '''reference''' to the array (see [https://en.wikipedia.org/wiki/Reference_(computer_science) Wikipedia reference page]);
_myFilledVariable = ["Weapon1","Weapon2"];
this means that if the array is edited, all the scripts/functions using a reference to this array will see the edition.
_count = [[count]] _myVariable; // Output: 2


// Error: Unexpected ","
[[private]] _myArray = ["a", "b", "c"];
_myErroneousArray = ["Weapon1","Weapon2","Weapon3",]; // The last element in an array must exclude the ","
[[private]] _myNewArray = _myArray;
_myArray [[set]] [1, "z"];
_myNewArray [[select]] 1; {{cc|will be "z"}}


</code>
An array set through [[setVariable]] does not need to be assigned again if you modify it by reference:
[[player]] [[setVariable]] ["myArray", ["a", "b", "c"]];
[[private]] _myArray = [[player]] [[getVariable]] "myArray";
_myArray [[set]] [1, "z"];
[[player]] [[getVariable]] "myArray"; {{cc|is ["a", "z", "c"]}}


=== Multi-dimensional arrays ===
=== Create an array ===
Multi-dimensional arrays are arrays within arrays. Associative arrays (i.e. "x" => [1,2,3],) are not a part of the language, however they can be approximated by creating a structure with a first element as a string and subsequent elements as arrays.


<code>// Multi-dimensional array example
{{cc|Example of an empty array}}
_multiArray1 = [["Item1",1,2,3],["Item2",4,5,6]];
[[private]] _myArray = [];
_count = [[count]] _multiArray1; // Output: 2
[[count]] _myArray; {{cc|returns 0}}
_count = [[count]] _multiArray1 select 0; // Output: 4
</code>
{{cc|Example of a filled array}}
<code>// Associative array approximation
[[private]] _myFilledArray = ["abc", "def"];
_assocTypeArray= [["Item1", ["My","Array","Elements"]],["Item2",["Smell","Like","Fromage"]]];
[[count]] _myFilledArray; {{cc|returns 2}}
_count = [[count]] _assocTypeArray; // Output: 2
_count = [[count]] _assocTypeArray select 0; // Output: 2  
_count = [[count]] ((_assocTypeArray select 0) select 1); // Output: 3
</code>


=== Referencing and setting element values ===
An array can hold another array within it, that can hold another array itself, etc:
Unlike in other languages, referencing elements within script is performed with the use of the [[select]] function. As script functions allow stacking of functions, select can be used multiple times, provided that each select returns an array which can be selected.
[[private]] _myArray = <nowiki>[["my", "subArray", 1], ["mySubArray2"], [["my", "sub", "sub", "array"]]];</nowiki>
[[count]] &nbsp;&nbsp;_myArray; {{cc|returns 3}}
[[count]] &nbsp;(_myArray [[select]] 0); {{cc|returns 3}}
[[count]] &nbsp;(_myArray [[select]] 1); {{cc|returns 1}}
[[count]] &nbsp;(_myArray [[select]] 2); {{cc|returns 1}}
[[count]] ((_myArray [[select]] 2) [[select]] 0); {{cc|returns 4}}


<code>//Selecting an element from a single-dimensional array
=== Getting an element ===
_mySingleArray = ["Select 0","Select 1","Select 2"];
_myArrayElement = _mySingleArray select 0; // Output: "Select 0" (string)


// Selecting from multi-dimensional arrays
An array uses a zero-based index for its elements:
_myMultiArray = [["Array1Elem1","Array1Elem2"],["Array2Elem1","Array2Elem2"]];
_selectFirst = _myMultiArray select 0; // Output: ["Array1Elem1","Array1Elem2"] (Array)
_count = count _selectFirst; // Output: 2


_selectSecond = (_myMultiArray select 0) select 0; // Output: "Array1Elem1" (String)
[[private]] _myArray = ["first item", "second item", "third item"];
</code>
_myArray [[select]] 0; {{cc|returns "first item"}}
_myArray [[a_hash_b|#]] 2; {{cc|returns "third item" - {{arma3}} only}}


If you want to change the value of an element within an array, then the [[set]] function must be used.
=== Setting an element ===
<code>// Set example
_mySingleArray = ["Item1","Item2];
_myFirstItem = _mySingleArray select 0; // Output: "Item1" (String)
_mySingleArray set [0,"Foo"]; // mySingleArray Output : ["Foo","Item2"]
_myFirstItem = _mySingleArray select 0; // Output: "Foo" (String)
</code>


If the index given by the [[set]] operator is out of bounds,
[[private]] _myArray = ["first item", "second item", "third item"];
* If the index rounded to a negative number, then an [[Error Zero Divisor]] message will be displayed in game.
_myArray [[select]] 1; {{cc|returns "second item"}}
* If the index rounded to a positive number, then the array will [[resize]] to incorporate the index ''as its last value''. Each element between the last valid element, and the new [[set]] element, will be the [[Nothing|null type]]
_myArray [[set]] [1, "hello there"]; {{cc|_myArray is ["first item", "hello there", "third item"]}}
 
{{Important | If the index given to the [[set]] command is out of bounds, the array will [[resize]] to incorporate the index ''as its last value''.
All the "empty spaces" between the last valid element and the new [[set]] element will be filled with [[nil]]}}
 
=== Counting elements ===
 
[[private]] _myArray = ["first item", "second item", "third item"];
[[count]] _myArray; {{cc|returns 3}}
 
=== Changing array size ===
 
The [[resize]] command is made to reduce or expand an array:
[[private]] _myArray = [1, 2, 3, 4, 5];
_myArray [[resize]] 3; {{cc|_myArray is [1, 2, 3]}}
 
[[private]] _myArray = [1, 2, 3];
_myArray [[resize]] 5; {{cc|_myArray is [1, 2, 3, [[nil]], [[nil]]]}}
 
{{Important | You do '''not''' need to extend an array before adding elements!}}
 
=== Array Copy ===
 
[[private]] _myArray = ["a", "b", "c"];
[[private]] _myNewArray = _myArray;
_myArray [[set]] [1, "z"];
_myNewArray [[select]] 1; {{cc|will be "z"}}
 
[[private]] _myArray = <nowiki>[["a", "b", "c"], ["d", "e", "f"];</nowiki>
[[private]] _subArray1 = _myArray [[select]] 0;
_subArray1 [[set]] [1, "z"];
{{cc|_subArray1 is now ["a", "z", "c"]}}
{{cc|_myArray is now <nowiki>[["a", "z", "c"], ["d", "e", "f"]]</nowiki>}}
 
In order to avoid this behaviour, '''copy''' the array with [[+|+ (plus)]]:
 
{{cc|making copy}}
[[private]] _myArray = ["a", "b", "c"];
[[private]] _myNewArray = [[+]]_myArray;
_myArray [[set]] [1, "z"];
_myNewArray [[select]] 1; {{cc|still "b"}}
 
Sub-arrays are also deep-copied {{Inline code|_myNewArray}} will not point at the same sub-array instances.
 
=== Adding (appending) elements ===
 
In {{arma3}} use [[append]] and [[pushBack]] commands:
 
[[private]] _myArray = [1, 2, 3];
_myArray [[pushBack]] 4; {{cc|_myArray is [1, 2, 3, 4]}}
_myArray [[append]] [5, 6]; {{cc|_myArray is [1, 2, 3, 4, 5, 6]}}
 
You could also use [[+| (+)]] operator to add arrays. The difference is that addition returns a copy of array and thus  [[Code Optimisation#Adding elements |a little slower]] than [[append]] and [[pushBack]], which modify target array.
 
[[private]] _myArray = [1, 2, 3];
_myArray = _myArray [[+]] [4]; {{cc|_myArray is [1, 2, 3, 4]}}
_myArray = _myArray [[+]] [5, 6]; {{cc|_myArray is [1, 2, 3, 4, 5, 6]}}
 
=== Removing (deleting) elements ===
 
In {{arma3}} the [[deleteAt]] and [[deleteRange]] commands are available:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
_myArray [[deleteAt]] 0; {{cc|_myArray is [2, 3, 4, 5]}}
 
[[private]] _myArray = [1, 2, 3, 4, 5];
_myArray [[deleteRange]] [1, 2]; {{cc|_myArray is [1, 4, 5]}}
 
You can also use [[-|(-)]] operator to subtract arrays. The subtraction returns array copy, just like addition, and this [[Code Optimisation#Removing elements|not as fast]] as [[deleteAt]] and [[deleteRange]] which modify target arrays.
 
[[private]] _myArray = [1, 2, 3, 4, 5];
_myArray = _myArray [[-]] [1]; {{cc|_myArray is [2, 3, 4, 5]}}
 
In {{arma3}} it became possible to also subtract nested arrays:
 
[[private]] _myArray = <nowiki>[[1, 2, 3], [4, 5, 6], [7, 8, 9]];</nowiki>
_myArray = _myArray [[-]] <nowiki>[[4, 5, 6]];</nowiki> {{cc|_myArray is <nowiki>[[1, 2, 3], [7, 8, 9]]</nowiki>}}
 
The subtraction will remove ''all'' elements of second array from the first array:
 
_myArray = [1, 2, 3, 1, 2, 3] [[-]] [1, 2]; {{cc|_myArray is [3, 3]}}
 
The solution to this issue is the combined use of [[set]] and an item that you know is '''not''' present in the array:
 
[[private]] _myArray = [1, 2, 3, 1, 2, 3];
_myArray [[set]] [2, [[objNull]]]; {{cc|_myArray is [1, 2, [[objNull]], 1, 2, 3]]}}
_myArray = _myArray [[-]] <nowiki>[</nowiki>[[objNull]]]; {{cc|_myArray is [1, 2, 1, 2, 3]}}
 
Using this technique, it is possible to mimic [[deleteRange]] behaviour this way:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
{ _myArray [[set]] [_x, [[objNull]]] } [[forEach]] [1, 2]; {{cc|_myArray is [1, [[objNull]], [[objNull]], 4, 5]}}
_array = _array [[-]] [objNull]; {{cc|_myArray is [1, 4, 5]}}
 
=== Going through the array ===
 
The simplest way to iterate through an array is the [[forEach]] command:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
{ [[systemChat]] [[str]] [[_x]] } [[forEach]] _myArray;
 
A combination of [[for]], [[count]] and [[select]] can also be used:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
[[for]] "_i" [[from]] 0 [[to]] '''([[count]] _myArray) -1''' [[do]] { {{cc|[[count]] would return 5, but 5 is at array index 4}}
[[systemChat]] [[str]] (_myArray [[select]] _i);
};
 
 
== Advanced usage ==
 
=== apply ===
 
Similar to the [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map "map" function in Javascript],
[[apply]] allows to apply code to every elements in an array and return a copy:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
_myArray = _myArray [[apply]] { [[_x]] [[*]] 2 }; {{cc|_myArray is [2, 4, 6, 8, 10]}}
{{cc|same as}}
_myArray = [[+]] _myArray;
[[for]] "_i" [[from]] 0 [[to]] [[count]] _myArray -1 [[do]] {
[[private]] _element = _myArray [[select]] _i;
_myArray [[set]] [_i, _element [[*]] 2];
};
 
=== select ===
 
A simple way to filter an array (and obtain a new one) is using [[select]]'s alternative syntax:
 
[[private]] _myArray = [1, 2, 3, 4, 5];
[[private]] _filteredArray = _myArray [[select]] { [[_x]] > 3 }; {{cc|_filteredArray is [4, 5]}}
{{cc|same as}}
[[private]] _filteredArray = [];
{ [[if]] ([[_x]] > 3) [[then]] { _filteredArray [[pushBack]] [[_x]] } } [[forEach]] _myArray;


Array variables behave the same as [[Object]] references, and differently to [[String]], [[Number]] and other variable types. An array variable holds a '''''pointer''''' to an array, or in other words, the location of an array. Any number of different variables can refer to the same array.
=== findIf ===


=== Adding (appending) to arrays ===
The [[findIf]] command was introduced in {{arma3}} and allows you to go through the whole list and stop '''as soon as the condition is met''', returning the condition-meeting element's array index:
Appending to arrays is done by the use of the + operator in the same way that a string is concatenated. However, each time + is used, a new array is created. In Arma 3 "array + array" operation has been significantly optimised and is very fast. You can also add array to array using [[append]] command. To just add an element to an existing array in ArmA3 use [[pushBack]].


<code>// Example of adding two single-dimensional arrays
[[private]] _myArray = [1, 2, 3, 4, 5];
_arrayOne = ["One"];
_myArray [[findIf]] { [[_x]] == 3 } > -1; {{cc|returns [[true]], meaning there is an element that equals 3}}
_arrayTwo = ["Two"];
_myArray [[findIf]] { [[_x]] == 6 } > -1; {{cc|returns [[false]], meaning there is no element that is equal to 6}}
_arrayThree = _arrayOne + _arrayTwo; // Output: ["One","Two"];
_arrayThree = _arrayOne append _arrayTwo; // Output: ["One","Two"];
_count = count _arrayThree; // Output: 2
_arrayOne pushBack "Two"; // ["One","Two"]
_count = count _arrayOne // Output: 2
</code>


===Looping to access elements===
You could use [[count]] to achieve the same result, however [[count]] won't stop until it iterated through the whole array, so it might take [[Code Optimisation#findIf|longer]].
To loop through elements within an array, the [[for]] or [[forEach]] functions can be used. The [[for]] function is useful for when you want to loop over a finite number of items, such as if you have only 20 units and want to loop from 1 to 20. For can be used along with the [[count]] function to loop through an array of any length. [[forEach]] provides a function which doesn't require a number to be provided or a condition; it will take the input of an array and run through each element automatically for you.  


In the [[for]] function, the user creates a variable inside quotes, such as "_x", which then refers to the current number as the for goes through the loop. In the [[forEach]], the function creates a [[Magic variable]] called "_x", which refers to the current item in the array as the foreach goes through the loop.
[[private]] _myArray = [1, 2, 3, 4, 5];
{ [[_x]] == 3 } [[count]] _myArray > 0; {{cc|returns [[true]], meaning there is an element that equals 3}}
{ [[_x]] == 6 } [[count]] _myArray > 0; {{cc|returns [[false]], meaning there is no element that is equal to 6}}


<code>//For Example
=== arrayIntersect ===
_myArray = ["One","Two","Three","Four"]; // 0 = "One", 1 = "Two", 2 = "Three", 3 = "Four"
_myCount = (count _myArray) -1;


//If we count the array, it will say "4", but we don't have an element "4" in the array, but we have 0,1,2,3. So remove 1 and we have the correct amount.
The [[arrayIntersect]] command returns a new array filled with the items found in both provided lists:
for "_x" from 0 to _myCount do
{
_currentElement = _myArray select _x; // Selects 0,1,2,3
[[diag_log]](_currentElement);
};


//The output will be:
[[private]] _array1 = [1, 2, 3, 4];
//"One"
[[private]] _array2 = [3, 4, 5, 6];
//"Two"
[[private]] _result = _array1 [[arrayIntersect]] _array2; {{cc|_result is [3, 4]}}
//"Three"
//"Four"
</code>


The foreach loop has a strange syntax, but nonetheless performs the same function. The forEach function '''begins with a bracket'' rather than with the forEach function name ({}forEach;).
'''You can remove duplicates (get unique items) with this command:'''


<code>//forEach example
[[private]] _myarray = [1, 2, 2, 3, 4];
_myArray = ["One","Two","Three","Four"]; // 0 = "One", 1 = "Two", 2 = "Three", 3 = "Four"
[[private]] _result = _myArray [[arrayIntersect]] _myArray; {{cc|_result is [1, 2, 3, 4]}}
{
[[diag_log]](_x);
} forEach _myArray;


// The output will be:
Be wary that [[nil]] elements get removed by this method:
// "One"
// "Two"
// "Three"
// "Four"
</code>


===Copying===
[[private]] _myarray = [1, 2, nil, 3, 4];
[[private]] _result = _myArray [[arrayIntersect]] _myArray; {{cc|_result is [1, 2, 3, 4]}}


This is done by the [[plus a|+]] unary operator. It copies an array, and sets the array variable to point to this new array.
=== Sorting an array ===


Example:<br>
==== sort ====
_array1 = [1,2,3]
_array2 = +_array1
Now _array1 and _array2 point to 2 different arrays, both of which have the contents [1,2,3].<br>


The [[sort]] command allows for sorting an array of [[String]], [[Number]] or sub-[[Array]]s of string/number. It modifies the original array and '''does not return anything''':


Note that a ''deep copy'' is made using the [[plus a|+]] unary operator.
[[private]] _myArray = ["zzz", "aaa", "ccc"];
_myArray [[sort]] [[true]]; {{cc|_myArray is ["aaa", "ccc", "zzz"]}}


Example:<br>
  [[private]] _myArray = [666, 57, 1024, 42];
  _a = [[1,1,1],[1,1,1]];
  _myArray [[sort]] [[false]]; {{cc|_myArray is [1024, 666, 57, 42]}}
  _b = +_a;
(_b select 0) set [0, 4];
Now _b is an array [[4,1,1],[1,1,1]], while _a is still [[1,1,1],[1,1,1]], meaning that a sub-array gets copied (''deeply'') instead of copying a pointer to the same/original sub-array.


Take a note that arrays are as immutable as objects, assigning a variable to another variable referencing array, does nto copy it.
[[private]] _myArray = <nowiki>[["zzz", 0], ["aaa", 42], ["ccc", 33]];</nowiki>
<code>
_myArray [[sort]] [[true]]; {{cc|_myArray is <nowiki>[["aaa", 42], ["ccc", 33], ["zzz", 0]]</nowiki>}}
b = [1,2,3];
c = b;
b set [0,4];
diag_log b;
diag_log c;
// both will output [4,2,3]
</code>


If you modify your array through the pointer, it's not necessary to rewrite it again with setVariable command, because you already change the original array.<br>
==== reverse ====
Example:<br>
<code>object setVariable ["myVar",[1,2,3]];
_array = object getVariable "myVar"; //[1,2,3]
_array set [0,-1];
object getVariable "myVar"; //[-1,2,3]
</code>


===Subtraction===
The [[reverse]] command simply reverses the array order:
[[private]] _myArray = [99, 33, 17, 24, "a", [3,2,1], 7777];
[[reverse]] _myArray; {{cc|_myArray is [7777, [3,2,1], "a", 24, 17, 33, 99]}}


This is done by the [[a - b|-]] binary operator. It takes 2 arrays, and returns a new array that contains all of the items in the first array that were '''''not''''' in the second array.
==== BIS_fnc_sortBy ====


Example:<br>
The function [[BIS_fnc_sortBy]] has been created for more complex sorting. Its algorithm input must return a number:
_array1 = [1,2,player,2,"String","String",3]<br>
_array2 = [2,player,"String"]<br>
_array3 = _array1 - _array2


The result is that _array3 is a new array which has the contents [1, 3].
[[private]] _closestHelicopters = <nowiki>[</nowiki>[_heli1, _heli2, _heli3], [], { [[player]] [[distance]] [[_x]] }, "ASCEND"] [[call]] [[BIS_fnc_sortBy]];


'''Note:'''<br>
*Subtracting an array from itself will always return an empty array [].


*Nested arrays ''cannot'' be subtracted - i.e. the following does NOT work:
== Common errors ==
_a1 = [[1,1],[2,2],[3,3]];
_a2 = <nowiki>[[</nowiki>2,2<nowiki>]]</nowiki>;
_a3 = _a1 - _a2; // will still return [[1,1],[2,2],[3,3]]


'''Workaround:'''
=== Index rounding ===
You can remove nested arrays by first replacing them with a non array variable.


Example:
In Arma scripts, indices are rounded to the nearest whole number.
<code>_array = [["first","hello1"],["second","hello2"],["third","hello3"]];
A boundary case (X.5, where X is any whole number) rounds to the nearest '''even''' whole number.
_array set [1,-1];
_array = _array - [-1];
// _array will now contain: [["first","hello1"],["third","hello3"]]
</code>


'''Arma 3:'''
;Boundary cases:
Subtraction from MultiArrays in Arma 3 works:
* -0.5 <= index <= 0.5 rounds to 0
_a1 = [[1,1],[2,2],[3,3]];
* &nbsp;0.5 <&nbsp; index <&nbsp; 1.5 rounds to 1
_a2 = <nowiki>[[</nowiki>2,2<nowiki>]]</nowiki>;
* &nbsp;1.5 <= index <= 2.5 rounds to 2
_a3 = _a1 - _a2; // will return [[1,1],[3,3]]
* &nbsp;2.5 <&nbsp; index <&nbsp; 3.5 rounds to 3


==Quirks and errors==
;In short:
===Index rounding===
* -0.5 rounds '''up''' to 0
In OFP script, indices are rounded to the nearest whole number.
* &nbsp;0.5 rounds '''down''' to 0
A bounday case (X.5, where X is any whole number) rounds to the nearest '''even''' whole number
* &nbsp;1.5 rounds '''up''' to 2
* &nbsp;2.5 rounds '''down''' to 2
* &nbsp;3.5 rounds '''up''' to 4
etc.


'''Boundary cases:'''<br>
=== Index out of Range ===
-0.5 rounds up to 0<br>
-0.5 <= index <= 0.5 rounds to 0<br>
0.5 rounds down to 0<br>
0.5 < index < 1.5 rounds to 1<br>
1.5 rounds up to 2<br>
1.5 <= index <= 2.5 rounds to 2<br>
2.5 rounds down to 2<br>
2.5 < index < 3.5 rounds to 3<br>
3.5 rounds up to 4<br>


Other indices follow this pattern.
The following code lists {{arma3}} behaviour on wrong indices:


===When an Array index is out of Range===
[[private]] _myArray = ["element0"];
If a rounded index refers to a position in an array that is invalid:
_myArray [[select]] -1; {{cc|throws a [[Error Zero Divisor]] error message}}
*If the index is negative, an [[Error Zero Divisor]] error message will be displayed.
_myArray [[select]] &nbsp;0; {{cc|returns "element0"}}
*If the index is positive, the returned value will be of the [[Nothing|null type]].
_myArray [[select]] &nbsp;1; {{cc|returns [[nil]]}}
_myArray [[select]] &nbsp;2; {{cc|throws a [[Error Zero Divisor]] error message}}


''Accesses which are out of bounds'':<br>
==== param ====
  _array = [];
Use the [[param]] command in order to avoid out of range error:
  _element = (_array select 0)
  [[private]] _myArray = [0,1,2];
  _myArray [[select]] 5; {{cc|error: out of range}}
_myArray [[param]] [5]; {{cc|returns [[nil]]}}
_myArray [[param]] [5, "abc"]; {{cc|returns default value "abc" on invalid index}}


_array = ["element"];
==== set ====
_element = (_array select 1)
If the index given to the [[set]] command is out of bounds:
* If the index rounded to a negative number, then an [[Error Zero Divisor]] message will be displayed in game.
* If the index rounded to a positive number, then the array will [[resize]] to incorporate the index ''as its last value''. Each element between the last valid element, and the new [[set]] element, will be the [[Nothing|null type]]


_array = ["element"];
=== Bad syntax ===
_element = (_array select -1)
''Accesses which are in bounds'':
_array = ["element"];
_element = (_array select 0)


  _array = ["element"];
  {{cc|Error: Unexpected ","}}
_element = (_array select 0.1)
[[private]] _myErroneousArray = ["Weapon1", "Weapon2", "Weapon3",]; {{cc|The last element in an array must exclude the ","}}


_array = ["element"];
_element = (_array select -0.3)


[[Category: Data Types]]
[[Category: Data Types]]

Revision as of 19:30, 1 September 2019

Template:SideTOC An Array is a list of items of varying variable types. Different types can coexist within the same array. An Array can either be one-dimensional or multi-dimensional.

Since Arma 3 v1.55.133789 arrays are limited to maximum of 9,999,999 (sometimes 10,000,000) elements


Working with arrays

Array properties

An array variable is a reference to the array (see Wikipedia reference page); this means that if the array is edited, all the scripts/functions using a reference to this array will see the edition.

private _myArray = ["a", "b", "c"];
private _myNewArray = _myArray;
_myArray set [1, "z"];
_myNewArray select 1; // will be "z"

An array set through setVariable does not need to be assigned again if you modify it by reference:

player setVariable ["myArray", ["a", "b", "c"]];
private _myArray = player getVariable "myArray";
_myArray set [1, "z"];
player getVariable "myArray"; // is ["a", "z", "c"]

Create an array

// Example of an empty array
private _myArray = [];
count _myArray;			// returns 0

// Example of a filled array
private _myFilledArray = ["abc", "def"];
count _myFilledArray;	// returns 2

An array can hold another array within it, that can hold another array itself, etc:

private _myArray = [["my", "subArray", 1], ["mySubArray2"], [["my", "sub", "sub", "array"]]];
count   _myArray;						// returns 3
count  (_myArray select 0);				// returns 3
count  (_myArray select 1);				// returns 1
count  (_myArray select 2);				// returns 1
count ((_myArray select 2) select 0);	// returns 4

Getting an element

An array uses a zero-based index for its elements:

private _myArray = ["first item", "second item", "third item"];
_myArray select 0;	// returns "first item"
_myArray # 2;		// returns "third item" - Arma 3 only

Setting an element

private _myArray = ["first item", "second item", "third item"];
_myArray select 1;					// returns "second item"
_myArray set [1, "hello there"];	// _myArray is ["first item", "hello there", "third item"]
If the index given to the set command is out of bounds, the array will resize to incorporate the index as its last value. All the "empty spaces" between the last valid element and the new set element will be filled with nil

Counting elements

private _myArray = ["first item", "second item", "third item"];
count _myArray; // returns 3

Changing array size

The resize command is made to reduce or expand an array:

private _myArray = [1, 2, 3, 4, 5];
_myArray resize 3; // _myArray is [1, 2, 3]
private _myArray = [1, 2, 3];
_myArray resize 5; // _myArray is [1, 2, 3, nil, nil]
You do not need to extend an array before adding elements!

Array Copy

private _myArray = ["a", "b", "c"];
private _myNewArray = _myArray;
_myArray set [1, "z"];
_myNewArray select 1; // will be "z"
private _myArray = [["a", "b", "c"], ["d", "e", "f"];
private _subArray1 = _myArray select 0;
_subArray1 set [1, "z"];
// _subArray1 is now ["a", "z", "c"]
// _myArray is now [["a", "z", "c"], ["d", "e", "f"]]

In order to avoid this behaviour, copy the array with + (plus):

// making copy
private _myArray = ["a", "b", "c"];
private _myNewArray = +_myArray;
_myArray set [1, "z"];
_myNewArray select 1; // still "b"

Sub-arrays are also deep-copied _myNewArray will not point at the same sub-array instances.

Adding (appending) elements

In Arma 3 use append and pushBack commands:

private _myArray = [1, 2, 3];
_myArray pushBack 4;		// _myArray is [1, 2, 3, 4]
_myArray append [5, 6];		// _myArray is [1, 2, 3, 4, 5, 6]

You could also use (+) operator to add arrays. The difference is that addition returns a copy of array and thus a little slower than append and pushBack, which modify target array.

private _myArray = [1, 2, 3];
_myArray = _myArray + [4];		// _myArray is [1, 2, 3, 4]
_myArray = _myArray + [5, 6];	// _myArray is [1, 2, 3, 4, 5, 6]

Removing (deleting) elements

In Arma 3 the deleteAt and deleteRange commands are available:

private _myArray = [1, 2, 3, 4, 5];
_myArray deleteAt 0; // _myArray is [2, 3, 4, 5]
private _myArray = [1, 2, 3, 4, 5];
_myArray deleteRange [1, 2];	// _myArray is [1, 4, 5]

You can also use (-) operator to subtract arrays. The subtraction returns array copy, just like addition, and this not as fast as deleteAt and deleteRange which modify target arrays.

private _myArray = [1, 2, 3, 4, 5];
_myArray = _myArray - [1]; // _myArray is [2, 3, 4, 5]

In Arma 3 it became possible to also subtract nested arrays:

private _myArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
_myArray = _myArray - [[4, 5, 6]]; // _myArray is [[1, 2, 3], [7, 8, 9]]

The subtraction will remove all elements of second array from the first array:

_myArray = [1, 2, 3, 1, 2, 3] - [1, 2]; // _myArray is [3, 3]

The solution to this issue is the combined use of set and an item that you know is not present in the array:

private _myArray = [1, 2, 3, 1, 2, 3];
_myArray set [2, objNull];			// _myArray is [1, 2, objNull, 1, 2, 3]]
_myArray = _myArray - [objNull];	// _myArray is [1, 2, 1, 2, 3]

Using this technique, it is possible to mimic deleteRange behaviour this way:

private _myArray = [1, 2, 3, 4, 5];
{ _myArray set [_x, objNull] } forEach [1, 2];	// _myArray is [1, objNull, objNull, 4, 5]
_array = _array - [objNull];					// _myArray is [1, 4, 5]

Going through the array

The simplest way to iterate through an array is the forEach command:

private _myArray = [1, 2, 3, 4, 5];
{ systemChat str _x } forEach _myArray;

A combination of for, count and select can also be used:

private _myArray = [1, 2, 3, 4, 5];
for "_i" from 0 to (count _myArray) -1 do { // count would return 5, but 5 is at array index 4
	systemChat str (_myArray select _i);
};


Advanced usage

apply

Similar to the "map" function in Javascript, apply allows to apply code to every elements in an array and return a copy:

private _myArray = [1, 2, 3, 4, 5];
_myArray = _myArray apply { _x * 2 }; // _myArray is [2, 4, 6, 8, 10]

// same as
_myArray = + _myArray;
for "_i" from 0 to count _myArray -1 do {
	private _element = _myArray select _i;
	_myArray set [_i, _element * 2];
};

select

A simple way to filter an array (and obtain a new one) is using select's alternative syntax:

private _myArray = [1, 2, 3, 4, 5];
private _filteredArray = _myArray select { _x > 3 }; // _filteredArray is [4, 5]

// same as
private _filteredArray = [];
{ if (_x > 3) then { _filteredArray pushBack _x } } forEach _myArray;

findIf

The findIf command was introduced in Arma 3 and allows you to go through the whole list and stop as soon as the condition is met, returning the condition-meeting element's array index:

private _myArray = [1, 2, 3, 4, 5];
_myArray findIf { _x == 3 } > -1; // returns true, meaning there is an element that equals 3
_myArray findIf { _x == 6 } > -1; // returns false, meaning there is no element that is equal to 6

You could use count to achieve the same result, however count won't stop until it iterated through the whole array, so it might take longer.

private _myArray = [1, 2, 3, 4, 5];
{ _x == 3 } count _myArray > 0; // returns true, meaning there is an element that equals 3
{ _x == 6 } count _myArray > 0; // returns false, meaning there is no element that is equal to 6

arrayIntersect

The arrayIntersect command returns a new array filled with the items found in both provided lists:

private _array1 = [1, 2, 3, 4];
private _array2 = [3, 4, 5, 6];
private _result = _array1 arrayIntersect _array2; // _result is [3, 4]

You can remove duplicates (get unique items) with this command:

private _myarray = [1, 2, 2, 3, 4];
private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]

Be wary that nil elements get removed by this method:

private _myarray = [1, 2, nil, 3, 4];
private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4]

Sorting an array

sort

The sort command allows for sorting an array of String, Number or sub-Arrays of string/number. It modifies the original array and does not return anything:

private _myArray = ["zzz", "aaa", "ccc"];
_myArray sort true; // _myArray is ["aaa", "ccc", "zzz"]
private _myArray = [666, 57, 1024, 42];
_myArray sort false; // _myArray is [1024, 666, 57, 42]
private _myArray = [["zzz", 0], ["aaa", 42], ["ccc", 33]];
_myArray sort true; // _myArray is [["aaa", 42], ["ccc", 33], ["zzz", 0]]

reverse

The reverse command simply reverses the array order:

private _myArray = [99, 33, 17, 24, "a", [3,2,1], 7777];
reverse _myArray; // _myArray is [7777, [3,2,1], "a", 24, 17, 33, 99]

BIS_fnc_sortBy

The function BIS_fnc_sortBy has been created for more complex sorting. Its algorithm input must return a number:

private _closestHelicopters = [[_heli1, _heli2, _heli3], [], { player distance _x }, "ASCEND"] call BIS_fnc_sortBy;


Common errors

Index rounding

In Arma scripts, indices are rounded to the nearest whole number. A boundary case (X.5, where X is any whole number) rounds to the nearest even whole number.

Boundary cases
  • -0.5 <= index <= 0.5 rounds to 0
  •  0.5 <  index <  1.5 rounds to 1
  •  1.5 <= index <= 2.5 rounds to 2
  •  2.5 <  index <  3.5 rounds to 3
In short
  • -0.5 rounds up to 0
  •  0.5 rounds down to 0
  •  1.5 rounds up to 2
  •  2.5 rounds down to 2
  •  3.5 rounds up to 4

etc.

Index out of Range

The following code lists Arma 3 behaviour on wrong indices:

private _myArray = ["element0"];
_myArray select -1; // throws a Error Zero Divisor error message
_myArray select  0; // returns "element0"
_myArray select  1; // returns nil
_myArray select  2; // throws a Error Zero Divisor error message

param

Use the param command in order to avoid out of range error:

private _myArray = [0,1,2];
_myArray select 5;			// error: out of range
_myArray param [5];			// returns nil
_myArray param [5, "abc"];	// returns default value "abc" on invalid index

set

If the index given to the set command is out of bounds:

  • If the index rounded to a negative number, then an Error Zero Divisor message will be displayed in game.
  • If the index rounded to a positive number, then the array will resize to incorporate the index as its last value. Each element between the last valid element, and the new set element, will be the null type

Bad syntax

// Error: Unexpected ","
private _myErroneousArray = ["Weapon1", "Weapon2", "Weapon3",]; // The last element in an array must exclude the ","