forEach: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Text replacement - "<tt>([^= ]+)<\/tt>" to "{{hl|$1}}")
(Some wiki formatting)
Line 26: Line 26:
|gr3= HashMap
|gr3= HashMap


|descr= Executes the given command(s) on every item of an array. In {{arma2}} and later, the variable [[Magic Variables#x|_x]] is always [[private]] to the [[forEach]] block so it is safe to nest them.
|descr= Executes the given command(s) on every item of an [[Array]] or a [[HashMap]].
{{Feature|arma2|Since {{arma2}}, the variable [[Magic Variables#x|_x]] is always [[private]] to the [[forEach]] block so it is safe to nest them (see {{HashLink|#Example 8}}).}}


|s1= code [[forEach]] array
|s1= code [[forEach]] array


|p1= code: [[String]] in {{ofp}} and {{arma1}}, [[Code]] since {{arma1}} - The array item that is currently being iterated over is represented by {{hl|[[Magic Variables#x|_x]]}}. The index of the current element is accessible via {{hl|[[Magic Variables#_forEachIndex|_forEachIndex]]}}
|p1= code: [[String]] in {{ofp}} and {{arma1}}, [[Code]] since {{arma1}} - available variables:
* {{hl|[[Magic Variables#x|_x]]}}: iterated item
* {{hl|[[Magic Variables#forEachIndex|_forEachIndex]]}}: item's index


|p2= array: [[Array]] - The array to iterate over
|p2= array: [[Array]] - The array to iterate over
Line 40: Line 43:
|s2since= arma3 2.02
|s2since= arma3 2.02


|p21= code: [[Code]] - Code applied to each key-value pair. The [[Magic Variables|Magic Variable]] {{hl|[[Magic Variables#x|_x]]}} contains the key, {{hl|[[Magic Variables#x|_y]]}} the value
|p21= code: [[Code]] - code applied to each key-value pair - available variables:
* {{hl|[[Magic Variables#x|_x]]}}: key
* {{hl|[[Magic Variables#x|_y]]}}: value
* {{hl|[[Magic Variables#forEachIndex|_forEachIndex]]}}: iteration number


|p22= hashMap : [[HashMap]] - The HashMap to iterate over
|p22= hashMap : [[HashMap]] - The HashMap to iterate over
Line 51: Line 57:
"[[Magic Variables#x|_x]] [[setDammage]] 1" [[forEach]] [[units]] [[player]]</code>
"[[Magic Variables#x|_x]] [[setDammage]] 1" [[forEach]] [[units]] [[player]]</code>


|x2= This command can also easily be used to execute a single command multiple times without respect to the array items.
|x2= This command can also easily be used to execute a single command multiple times without respect to the array items - see also [[for]]
<code>{ [[player]] [[addMagazine]] "30Rnd_556x45_Stanag"; } [[forEach]] [1, 2, 3, 4];</code>
<code>{ [[player]] [[addMagazine]] "30Rnd_556x45_Stanag" } [[forEach]] [1, 2, 3, 4];
{{cc|equivalent to}}
[[for]] "_i" [[from]] 1 [[to]] 4 [[do]] { [[player]] [[addMagazine]] "30Rnd_556x45_Stanag" };</code>


|x3= You can also use multiple commands in the same block:
|x3= You can also use multiple commands in the same block:
Line 62: Line 70:


|x4= To get the index of a [[forEach]] loop, use [[Magic Variables#forEachIndex|_forEachIndex]]:
|x4= To get the index of a [[forEach]] loop, use [[Magic Variables#forEachIndex|_forEachIndex]]:
<code>{ [[systemChat]] [[str]] _forEachIndex]; } [[forEach]] [1,2,3]; {{cc|will return: "0", "1", "2" in [[systemChat]] messages}}</code>
<code>{ [[systemChat]] [[str]] [[Magic Variables#forEachIndex|_forEachIndex]]; } [[forEach]] ["a", "b", "c"]; {{cc|will return: "0", "1", "2" in [[systemChat]] messages}}</code>


|x5= Iterating a [[HashMap]] [[Magic Variables#forEachIndex|_forEachIndex]]:
|x5= Iterating a [[HashMap]]'s [[Magic Variables#forEachIndex|_forEachIndex]]:
<code>{ [[systemChat]] [[format]] ["%1-%2", _x, _y]; } [[forEach]] [[createHashMapFromArray]] [[1,"a"], [2,"b"]]; {{cc|will return: "1-a", "2-b" in [[systemChat]] messages}}</code>
<code>{{cc|shows "0, k1, v1", "1, k2, v2" in [[systemChat]] messages}}
{
[[systemChat]] [[format]] ["%1, %2, %3", _forEachIndex, _x, _y];
} [[forEach]] [[createHashMapFromArray]] [
["k1", "v1"],
["k2", "v2"]
];</code>


|x6= <code>{
|x6= [[findIf]] equivalent for [[HashMap]]:<code>[[private]] _resultKey = {
[[if]] ([[Magic Variables#forEachIndex|_forEachIndex]] == 1) [[then]] {
[[if]] (_y [[isEqualTo]] "wantedValue") [[exitWith]] { _x };
{{cc|Copilot}}
""
_x [[addUniform]] "U_B_Soldier_VR";
} [[forEach]] _hashmap;</code>
} [[else]] {
{{cc|Adams}}
[_x, "B_Soldier_TL_F"] [[call]] [[BIS_fnc_loadInventory]];
_x [[addUniform]] "U_B_Soldier_VR";
_x [[setIdentity]] "Bootcamp_B_Adams";
};
} [[forEach]] _crew;</code>


|seealso= [[Control Structures]] [[for]] [[apply]] [[while]] [[select]] [[findIf]] [[count]]
|x7= Array is edited by reference:
}}
 
<dl class="command_description">
 
<dt><dt>
<dd class="notedate">Posted on July 20, 2010</dd>
<dt class="note">[[User:Kronzky|Kronzky]]</dt>
<dd class="note">
If arrays are used in forEach loops, _x uses them by reference, so any changes to _x will be applied to the original:
<code>_arr1 = [1,2,3];
<code>_arr1 = [1,2,3];
_arr2 = [6,7,8];
_arr2 = [6,7,8];
{ [[Magic Variables#x|_x]] [[set]] [1,"x"] } [[forEach]] [_arr1,_arr2];</code>
_arr3 = [0];
will change _arr1 to [1,"x",3], and _arr2 to [6,"x",8].
{ [[Magic Variables#x|_x]] [[set]] [1, "changed"] } [[forEach]] [_arr1, _arr2, _arr3];
{{cc|1= _arr1 = [1, "changed", 3]}}
{{cc|1= _arr2 = [6, "changed", 8]}}
{{cc|1= _arr3 = [0, "changed"]}}</code>


<dd class="notedate">Posted on January 2, 2015 - 22:35 (UTC)</dd>
|x8= <code>{
<dt class="note">[[User:Heeeere's Johnny!|Heeeere's Johnny!]]</dt>
[[private]] _verticalValue = _x; {{cc|needed, otherwise _horizontalValues' _x made this one inaccessible}}
<dd class="note">
{
[_x, _verticalValue] [[call]] TAG_fnc_doSomething;
} [[forEach]] _horizontalValues;
} [[forEach]] _verticalValues;</code>


Using [[exitWith]] inside a '''forEach''' loop will make '''forEach''' actually return something, namely whatever the '''exitWith''' returns:
|seealso= [[Control Structures]] [[for]] [[apply]] [[while]] [[select]] [[findIf]] [[count]]  
<code>_result = {
}}
    if(_x [[isEqualTo]] 3) [[exitWith]] {"Hello"}
} '''forEach''' [1,2,3,4,5];
//_result = "Hello"</code>
</dd>


<dt><dt>
{{Note
<dd class="notedate">Posted on November 28, 2017 - 13:46 (UTC)</dd>
|user= dedmen
<dt class="note">[[User:dedmen|dedmen]]</dt>
|timestamp= 20171128134600
<dd class="note">
|text= Be careful when deleting ([[deleteAt]]) elements from an Array while you iterate over it.<br>
Be careful when deleting ([[deleteAt]]) elements from an Array while you iterate over it.<br>
[[forEachIndex|_forEachIndex]] will not move to reflect your change.<br>
[[forEachIndex|_forEachIndex]] will not move to reflect your change.<br>


The forEach code is doing the same as
The forEach code is doing the same as
<code>_forEachIndex = 0;
<code>[[private]] _forEachIndex = 0;
while {_forEachIndex < count _array} do {
[[while]] { [[Magic Variables#forEachIndex|_forEachIndex]] < [[count]] _array } [[do]]
     (_array select _forEachIndex) call code;
{
     _forEachIndex = _forEachIndex + 1;
     (_array [[select]] [[Magic Variables#forEachIndex|_forEachIndex]]) [[call]] code;
     [[Magic Variables#forEachIndex|_forEachIndex]] = [[Magic Variables#forEachIndex|_forEachIndex]] + 1;
}</code>
}</code>


Line 122: Line 122:
Example:
Example:
<code>_array = [1,2,3,4,5,6];
<code>_array = [1,2,3,4,5,6];
{_array deleteAt _forEachIndex} forEach _array;
{ _array [[deleteAt]] [[Magic Variables#forEachIndex|_forEachIndex]] } [[forEach]] _array;</code>
</code>
After the first iteration your Array will be [2,3,4,5,6] and the _forEachIndex will be 1.<br>
After the first iteration your Array will be [2,3,4,5,6] and the _forEachIndex will be 1.<br>
So on next iteration you get the element at index 1 which will be 3. So you've just skipped the 2.<br>
So on next iteration you get the element at index 1 which will be 3. So you've just skipped the 2.<br>
So in the end you will only iterate over 1,3 and 6.
So in the end you will only iterate over 1,3 and 6.
</dd>
}}
 
</dl>

Revision as of 16:41, 18 December 2021

Hover & click on the images for description

Description

Description:
Executes the given command(s) on every item of an Array or a HashMap.
Arma 2
Since Arma 2, the variable _x is always private to the forEach block so it is safe to nest them (see Example 8).
Groups:
Program FlowArraysHashMap

Syntax

Syntax:
code forEach array
Parameters:
code: String in Operation Flashpoint and Armed Assault, Code since Armed Assault - available variables:
array: Array - The array to iterate over
Return Value:
Anything - Will return the value of last executed statement

Alternative Syntax

Syntax:
code forEach hashMap
Parameters:
code: Code - code applied to each key-value pair - available variables:
hashMap : HashMap - The HashMap to iterate over
Return Value:
Anything - Will return the value of last executed statement

Examples

Example 1:
// SQF { _x setDamage 1 } forEach units player; ; SQS "_x setDammage 1" forEach units player
Example 2:
This command can also easily be used to execute a single command multiple times without respect to the array items - see also for { player addMagazine "30Rnd_556x45_Stanag" } forEach [1, 2, 3, 4]; // equivalent to for "_i" from 1 to 4 do { player addMagazine "30Rnd_556x45_Stanag" };
Example 3:
You can also use multiple commands in the same block: { _x setCaptive true; removeAllWeapons _x; doStop _x; } forEach units group this;
Example 4:
To get the index of a forEach loop, use _forEachIndex: { systemChat str _forEachIndex; } forEach ["a", "b", "c"]; // will return: "0", "1", "2" in systemChat messages
Example 5:
Iterating a HashMap's _forEachIndex: // shows "0, k1, v1", "1, k2, v2" in systemChat messages { systemChat format ["%1, %2, %3", _forEachIndex, _x, _y]; } forEach createHashMapFromArray [ ["k1", "v1"], ["k2", "v2"] ];
Example 6:
findIf equivalent for HashMap:private _resultKey = { if (_y isEqualTo "wantedValue") exitWith { _x }; "" } forEach _hashmap;
Example 7:
Array is edited by reference: _arr1 = [1,2,3]; _arr2 = [6,7,8]; _arr3 = [0]; { _x set [1, "changed"] } forEach [_arr1, _arr2, _arr3]; // _arr1 = [1, "changed", 3] // _arr2 = [6, "changed", 8] // _arr3 = [0, "changed"]
Example 8:
{ private _verticalValue = _x; // needed, otherwise _horizontalValues' _x made this one inaccessible { [_x, _verticalValue] call TAG_fnc_doSomething; } forEach _horizontalValues; } forEach _verticalValues;

Additional Information

See also:
Control Structures for apply while select findIf count

Notes

Report bugs on the Feedback Tracker and/or discuss them on the Arma Discord or on the Forums.
Only post proven facts here! Add Note
dedmen - c
Posted on Nov 28, 2017 - 13:46 (UTC)
Be careful when deleting (deleteAt) elements from an Array while you iterate over it.
_forEachIndex will not move to reflect your change.
The forEach code is doing the same as private _forEachIndex = 0; while { _forEachIndex < count _array } do { (_array select _forEachIndex) call code; _forEachIndex = _forEachIndex + 1; } So if you delete your current element from the array the other elements will shift forward. Meaning you skip one element.
Example: _array = [1,2,3,4,5,6]; { _array deleteAt _forEachIndex } forEach _array; After the first iteration your Array will be [2,3,4,5,6] and the _forEachIndex will be 1.
So on next iteration you get the element at index 1 which will be 3. So you've just skipped the 2.
So in the end you will only iterate over 1,3 and 6.