Array: Difference between revisions
Lou Montana (talk | contribs) m (Fix) |
|||
(6 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{TOC|side}} | {{TOC|side}} | ||
An '''Array''' is a list of items of varying [[:Category:Data Types|variable types]]. Different types can coexist within the same array | An '''Array''' is a list of items of varying [[:Category:Data Types|variable types]] (including other arrays). Different types can coexist within the same array. | ||
See also: [[:Category:Arrays|Arrays]] | See also: [[:Category:Arrays|Arrays]] | ||
{{Feature | | {{Feature|warning|Since {{arma3}} v1.56, arrays are limited to maximum of '''9,999,999''' (sometimes 10,000,000) elements.}} | ||
== Working | == Working With Arrays == | ||
=== Array | === Array Properties === | ||
An array variable is a '''reference''' to the array (see {{ | An array variable is a '''reference''' to the array (see {{Link|https://en.wikipedia.org/wiki/Reference_(computer_science)|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. | this means that if the array is edited, all the scripts/functions using a reference to this array will see the edition. | ||
Line 29: | Line 28: | ||
</sqf> | </sqf> | ||
=== | === Array Creation === | ||
<sqf> | <sqf> | ||
Line 60: | Line 59: | ||
</sqf> | </sqf> | ||
=== Setting an | === Setting an Element === | ||
<sqf> | <sqf> | ||
Line 82: | Line 81: | ||
The [[resize]] command is made to reduce or expand an array: | The [[resize]] command is made to reduce or expand an array: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
_myArray resize 3; // _myArray is [ | _myArray resize 3; // _myArray is ["a", "b", "c"] | ||
</sqf> | </sqf> | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c"]; | ||
_myArray resize 5; // _myArray is [ | _myArray resize 5; // _myArray is ["a", "b", "c", nil, nil] | ||
</sqf> | </sqf> | ||
{{Feature | important | You do '''not''' need to extend an array before adding elements | {{Feature|important|You do '''not''' need to extend an array before adding any elements.}} | ||
=== Array Copy === | === Array Copy === | ||
Line 119: | Line 118: | ||
Sub-arrays are also deep-copied; {{hl|_myNewArray}} will not point at the same sub-array instances. | Sub-arrays are also deep-copied; {{hl|_myNewArray}} will not point at the same sub-array instances. | ||
=== Adding ( | === Adding (Appending) Elements === | ||
In {{arma3}} use [[append]] and [[pushBack]] commands: | In {{arma3}} use [[append]] and [[pushBack]] commands: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c"]; | ||
_myArray pushBack | _myArray pushBack "d"; // _myArray is ["a", "b", "c", "d"] - pushback = add the element at the end | ||
_myArray append [ | _myArray append ["e", "f"]; // _myArray is ["a", "b", "c", "d", "e", "f"] - append = pushback for each provided items | ||
</sqf> | </sqf> | ||
You could also use [[+|(+)]] operator to add arrays. | You could also use the [[+|plus (+)]] operator to add arrays. | ||
The difference is that addition returns a copy of array and thus | 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 the target array. | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c"]; | ||
_myArray = _myArray + [ | _myArray = _myArray + ["d"]; // _myArray is ["a", "b", "c", "d"] | ||
_myArray = _myArray + [ | _myArray = _myArray + ["e", "f"]; // _myArray is ["a", "b", "c", "d", "e", "f"] | ||
</sqf> | </sqf> | ||
=== Removing ( | === Removing (Deleting) Elements === | ||
In {{arma3}} the [[deleteAt]] and [[deleteRange]] commands are available: | In {{arma3}} the [[deleteAt]] and [[deleteRange]] commands are available: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
_myArray deleteAt 0; // _myArray is [ | _myArray deleteAt 0; // _myArray is ["b", "c", "d", "e"] | ||
</sqf> | </sqf> | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
_myArray deleteRange [1, 2]; // _myArray is [ | _myArray deleteRange [1, 2]; // _myArray is ["a", "d", "e"] | ||
</sqf> | </sqf> | ||
You can also use [[-|(-)]] operator to subtract arrays. The subtraction returns array copy, just like addition, and | You can also use the [[-|minus (-)]] operator to subtract arrays. | ||
The subtraction returns array copy, just like addition, and is [[Code Optimisation#Removing elements|not as fast]] as [[deleteAt]] and [[deleteRange]] which modify target arrays. | |||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
_myArray = _myArray - [ | _myArray = _myArray - ["a"]; // _myArray is ["b", "c", "d", "e"] | ||
</sqf> | </sqf> | ||
In {{arma3}} it became possible to also subtract nested arrays: | In {{arma3}} it became possible to also subtract nested arrays: | ||
<sqf> | <sqf> | ||
private _myArray = [[ | private _myArray = [["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]; | ||
_myArray = _myArray - [[ | _myArray = _myArray - [["d", "e", "f"]]; // _myArray is [["a", "b", "c"], ["g", "h", "i"]] | ||
</sqf> | </sqf> | ||
The subtraction will remove ''all'' elements of second array from the first | The subtraction will remove ''all'' elements of the second array from the first one: | ||
<sqf>_myArray = [ | <sqf>_myArray = ["a", "b", "c", "a", "b", "c"] - ["a", "b"]; // _myArray is ["c", "c"]</sqf> | ||
The solution to this issue is the combined use of [[set]] and an item that you know is '''not''' present in the array: | The solution to this issue is the combined use of [[set]] and an item that you know is '''not''' present in the array: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "a", "b", "c"]; | ||
_myArray set [2, objNull]; // _myArray is [ | _myArray set [2, objNull]; // _myArray is ["a", "b", objNull, "a", "b", "c"] | ||
_myArray = _myArray - [objNull]; // _myArray is [ | _myArray = _myArray - [objNull]; // _myArray is ["a", "b", "a", "b", "c"] | ||
</sqf> | </sqf> | ||
Using this technique, it is possible to mimic [[deleteRange]] behaviour this way: | Using this technique, it is possible to mimic [[deleteRange]] behaviour this way: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
{ _myArray set [_x, objNull] } forEach [1, 2]; // _myArray is [ | { _myArray set [_x, objNull] } forEach [1, 2]; // _myArray is ["a", objNull, objNull, "d", "e"] | ||
_array = _array - [objNull]; // _myArray is [ | _array = _array - [objNull]; // _myArray is ["a", "d", "e"] | ||
</sqf> | </sqf> | ||
=== Going | === Going Through the Array === | ||
The simplest way to iterate through an array is the [[forEach]] command: | The simplest way to iterate through an array is the [[forEach]] command: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
{ systemChat | { systemChat _x } forEach _myArray; | ||
</sqf> | </sqf> | ||
A combination of [[for]], [[count]] and [[select]] can also be used: | A combination of [[for]], [[count]] and [[select]] can also be used: | ||
<sqf> | <sqf> | ||
private _myArray = [ | private _myArray = ["a", "b", "c", "d", "e"]; | ||
for "_i" from 0 to (count _myArray) -1 do { // count | for "_i" from 0 to (count _myArray) -1 do { // count returns 5, but it is a zero-based index | ||
systemChat | systemChat (_myArray select _i); | ||
}; | }; | ||
</sqf> | </sqf> | ||
== Advanced | == Advanced Usage == | ||
=== apply === | === apply === | ||
Similar to the | Similar to the {{Link|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: | [[apply]] allows to apply code to every elements in an array and return a copy: | ||
<sqf> | <sqf> | ||
Line 204: | Line 204: | ||
_myArray = _myArray apply { _x * 2 }; // _myArray is [2, 4, 6, 8, 10] | _myArray = _myArray apply { _x * 2 }; // _myArray is [2, 4, 6, 8, 10] | ||
// same as | // same as (but faster than) | ||
_myArray = + _myArray; | _myArray = + _myArray; | ||
for "_i" from 0 to count _myArray -1 do { | for "_i" from 0 to count _myArray -1 do | ||
{ | |||
private _element = _myArray select _i; | private _element = _myArray select _i; | ||
_myArray set [_i, _element * 2]; | _myArray set [_i, _element * 2]; | ||
Line 251: | Line 252: | ||
'''You can remove duplicates (get unique items) with this command:''' | '''You can remove duplicates (get unique items) with this command:''' | ||
<sqf> | <sqf> | ||
private | private _myArray = [1, 2, 2, 3, 4]; | ||
private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4] | private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4] | ||
</sqf> | </sqf> | ||
Line 257: | Line 258: | ||
Be wary that [[nil]] elements get removed by this method: | Be wary that [[nil]] elements get removed by this method: | ||
<sqf> | <sqf> | ||
private | private _myArray = [1, 2, nil, 3, 4]; | ||
private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4] | private _result = _myArray arrayIntersect _myArray; // _result is [1, 2, 3, 4] | ||
</sqf> | </sqf> | ||
=== Sorting | === Selective Removal === | ||
Selectively filter out single elements from {{hl|_arrayA}} based on {{hl|_arrayB}}.<br> | |||
This is useful in the case where ''some'' duplicates must be removed. | |||
<sqf> | |||
private _arrayA = [1, 2, 3, 2, 4, 5, 4]; | |||
private _arrayB = [2, 2, 4]; | |||
{ | |||
private _index = _arrayA find _x; | |||
if (_index != -1) then | |||
{ | |||
_arrayA deleteAt _index; | |||
}; | |||
} forEach _arrayB; | |||
_arrayA; // is now [1, 3, 5, 4] | |||
</sqf> | |||
=== Sorting === | |||
==== sort ==== | ==== sort ==== | ||
Line 286: | Line 307: | ||
==== BIS_fnc_sortBy ==== | ==== BIS_fnc_sortBy ==== | ||
The function [[BIS_fnc_sortBy]] has been created for more complex sorting. Its algorithm input must return a number: | The function [[BIS_fnc_sortBy]] has been created for more complex sorting. Its algorithm input must return a number: | ||
<sqf>private _closestHelicopters = [[_heli1, _heli2, _heli3], [], { player distance _x }, "ASCEND"] call BIS_fnc_sortBy;</sqf> | <sqf>private _closestHelicopters = [[_heli1, _heli2, _heli3], [], { player distance _x }, "ASCEND"] call BIS_fnc_sortBy;</sqf> | ||
== Common | == Common Errors == | ||
=== Index | === Index Rounding === | ||
In | In {{Link|Real Virtuality}} 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. | A boundary case (X.5, where X is any whole number) rounds to the nearest '''even''' whole number. | ||
;Boundary cases: | ; Boundary cases: | ||
* -0.5 <= index <= 0.5 rounds to 0 | * -0.5 <= index <= 0.5 rounds to 0 | ||
* 0.5 < index < 1.5 rounds to 1 | * 0.5 < index < 1.5 rounds to 1 | ||
Line 304: | Line 324: | ||
* 2.5 < index < 3.5 rounds to 3 | * 2.5 < index < 3.5 rounds to 3 | ||
;In short: | ; In short: | ||
* -0.5 rounds '''up''' to 0 | * -0.5 rounds '''up''' to 0 | ||
* 0.5 rounds '''down''' to 0 | * 0.5 rounds '''down''' to 0 | ||
Line 311: | Line 331: | ||
* 3.5 rounds '''up''' to 4 | * 3.5 rounds '''up''' to 4 | ||
etc. | etc. | ||
{{Feature|informative|This behaviour is different from {{Link|random}}'s behaviour.}} | |||
=== Index out of Range === | === Index out of Range === | ||
Line 326: | Line 347: | ||
Use the [[param]] command in order to avoid out of range error: | Use the [[param]] command in order to avoid out of range error: | ||
<sqf> | <sqf> | ||
private _myArray = [0,1,2]; | private _myArray = [0, 1, 2]; | ||
_myArray select 5; // error: out of range | _myArray select 5; // error: out of range | ||
_myArray param [5]; // returns nil | _myArray param [5]; // returns nil | ||
_myArray param [5, "abc"]; // returns default value "abc" on invalid index | _myArray param [5, "abc"]; // returns default value "abc" on invalid index | ||
</sqf> | </sqf> | ||
{{Feature|informative|See also [[params]] to define multiple items at once.}} | |||
==== set ==== | ==== set ==== | ||
If the index given to the [[set]] command is out of bounds: | 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]] | ||
=== Zero Divisor === | |||
See above - a used array index may be negative. | |||
=== | === Unexpected "," === | ||
This error originates from a bad syntax: | |||
<sqf> | <sqf> | ||
private _myErroneousArray = ["Weapon1", "Weapon2", "Weapon3",]; // The last element in an array must not end by "," | private _myErroneousArray = ["Weapon1", "Weapon2", "Weapon3",]; // The last element in an array must not end by "," | ||
// this mostly happens in vertical arrays | |||
private _myErroneousArray = [ | |||
"element1", | |||
"element2", | |||
"element3", // this one comma is wrong | |||
]; | |||
</sqf> | </sqf> | ||
=== | === Reserved variable in expression === | ||
This issue arises when trying to modify a read-only array (such as {{Link|select}} arrays that are returned from an addon, or eventually a trigger's {{Link|Magic Variables#thisList|thisList}}). | |||
To combat this, ''copy'' said array with the {{Link|+|plus (+)}} command before modifying: | |||
<sqf> | <sqf> | ||
// | private _readOnlyArray = thisList; // assuming the code is called from within a trigger | ||
_readOnlyArray set [1, "test"]; // Error: Reserved variable in expression - thisList return value is read-only | |||
// No Error | // No Error | ||
private _normalArray = +_readOnlyArray; // shallow-copy the array instead of using a reference | |||
_normalArray set [1, "test"]; // perfectly fine | |||
</sqf> | </sqf> | ||
== See Also == | == See Also == |
Latest revision as of 19:49, 26 May 2024
An Array is a list of items of varying variable types (including other arrays). Different types can coexist within the same array.
See also: Arrays
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.
An array set through setVariable does not need to be assigned again if you modify it by reference:
Array Creation
An array can hold another array within it, that can hold another array itself, etc:
Getting an element
An array uses a zero-based index for its elements:
Setting an Element
Counting elements
Changing array size
The resize command is made to reduce or expand an array:
Array Copy
In order to avoid this behaviour, copy the array with + (plus):
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:
You could also use the plus (+) 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 the target array.
Removing (Deleting) Elements
In Arma 3 the deleteAt and deleteRange commands are available:
You can also use the minus (-) operator to subtract arrays. The subtraction returns array copy, just like addition, and is not as fast as deleteAt and deleteRange which modify target arrays.
In Arma 3 it became possible to also subtract nested arrays:
The subtraction will remove all elements of the second array from the first one:
The solution to this issue is the combined use of set and an item that you know is not present in the array:
Using this technique, it is possible to mimic deleteRange behaviour this way:
Going Through the Array
The simplest way to iterate through an array is the forEach command:
A combination of for, count and select can also be used:
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:
select
A simple way to filter an array (and obtain a new one) is using select's alternative syntax:
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:
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.
arrayIntersect
The arrayIntersect command returns a new array filled with the items found in both provided lists:
You can remove duplicates (get unique items) with this command:
Be wary that nil elements get removed by this method:
Selective Removal
Selectively filter out single elements from _arrayA based on _arrayB.
This is useful in the case where some duplicates must be removed.
Sorting
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:
reverse
The reverse command simply reverses the array order:
BIS_fnc_sortBy
The function BIS_fnc_sortBy has been created for more complex sorting. Its algorithm input must return a number:
Common Errors
Index Rounding
In Real Virtuality 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:
param
Use the param command in order to avoid out of range error:
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
Zero Divisor
See above - a used array index may be negative.
Unexpected ","
This error originates from a bad syntax:
Reserved variable in expression
This issue arises when trying to modify a read-only array (such as select arrays that are returned from an addon, or eventually a trigger's thisList).
To combat this, copy said array with the plus (+) command before modifying: