forEach: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (Text replacement - "\[\[Category:[ _]?Scripting[ _]Commands[ _]Armed[ _]Assault(\|.*)]]" to "{{GameCategory|arma1|Scripting Commands}}")
m (Text replacement - "Samatra" to "Sa-Matra")
 
(44 intermediate revisions by 4 users not shown)
Line 1: Line 1:
{{Command|Comments=
{{RV|type=command
____________________________________________________________________________________________


| ofp |Game name=
|game1= ofp
|version1= 1.00


|gr1= Program Flow |GROUP1=
|game2= ofpe
|version2= 1.00


|1.00|Game version=
|game3= arma1
____________________________________________________________________________________________
|version3= 1.00


| Executes the given command(s) on every item of an array.<br>
|game4= arma2
The array items are represented by the [[Magic Variables|magic variable]] '''[[_x]]'''. The array indices are represented by '''[[_forEachIndex]]'''.<br>
|version4= 1.00
In {{arma2}} and later, the variable [[_x]] is always local to the [[forEach]] block so it is safe to nest them.<br>
{{since|arma3|2.01|y}} the [[HashMap]] variant also provides a _y variable for the Value in the key-value pair.
|DESCRIPTION=
____________________________________________________________________________________________


| code [[forEach]] array |SYNTAX=
|game5= arma2oa
|version5= 1.50


|p1= code:
|game6= tkoh
* [[String]] ({{ofp}}&nbsp;/&nbsp;{{arma1}})
|version6= 1.00
* [[Code]] ({{arma1}} and later) |PARAMETER1=


|p2= array: [[Array]] - the array to iterate |PARAMETER2=
|game7= arma3
|version7= 0.50


| [[Anything]] - will return the value of last executed statement |RETURNVALUE=
|gr1= Program Flow
|gr2= Arrays
|gr3= HashMap


____________________________________________________________________________________________
|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 {{Link|#Example 8}}).}}
| s2= code [[forEach]] hashMap |SYNTAX4=


| p21= code: [[Code]] |Parameter21=
|s1= code [[forEach]] array
| p22= hashMap : [[HashMap]] - The HashMap to iterate through |Parameter22=


| r2= [[Anything]] - will return the value of last executed statement |RETURNVALUE2=
|p1= <nowiki/>
{{{!}} class="wikitable align-center float-right"
! Game
{{!}} {{GVI|ofp|1.00}}
{{!}} {{GVI|arma1|1.00}}
{{!}} {{GVI|arma2|1.00}}
{{!}} {{GVI|arma2oa|1.50}}
{{!}} {{GVI|arma3|1.00}}
{{!}} {{GVI|tkoh|1.00}}
{{!}}-
! [[String]] support
{{!}} colspan="2" {{!}} {{Icon|checked}}
{{!}} colspan="4" {{!}} {{Icon|unchecked}}
{{!}}-
! [[Code]] support
{{!}} {{Icon|unchecked}}
{{!}} colspan="5" {{!}} {{Icon|checked}}
{{!}}}
code: [[String]] only in {{ofp}} and {{arma1}}, {{GVI|arma1|1.00|size= 0.75}} [[Code]] since {{arma1}} - available variables:
* {{hl|[[Magic Variables#x|_x]]}}: iterated item
* {{GVI|arma2oa|1.55|size= 0.75}} {{hl|[[Magic Variables#forEachIndex|_forEachIndex]]}}: item's index


____________________________________________________________________________________________
|p2= array: [[Array]] - the array to iterate over
 
|x1= <code>{{cc|SQF}}
{ [[_x]] [[setDamage]] 1 } [[forEach]] [[units]] [[group]] [[player]];</code>
<code>{{codecomment|; SQS}}
"[[_x]] [[setDammage]] 1" [[forEach]] [[units]] [[group]] [[player]]</code> |EXAMPLE1=


|x2= This command can also easily be used to execute a single command multiple times without respect to the array items.
|r1= [[Anything]] - will return the value of last executed statement
<code>{ [[player]] [[addMagazine]] "30Rnd_556x45_Stanag"; } [[forEach]] [1, 2, 3, 4];</code> |EXAMPLE2=


|x3= You can also use multiple commands in the same block:
|s2= code [[forEach]] hashMap
<code>{
 
    [[Magic Variables|_x]] [[setCaptive]] [[true]];
|s2since= arma3 2.02
    [[removeAllWeapons]] [[Magic Variables|_x]];
    [[doStop]] [[Magic Variables|_x]];
} [[forEach]] [[units]] [[group]] [[this]];</code> |EXAMPLE3=


|x4= To get the index of a [[forEach]] loop, use [[_forEachIndex]]:
|p21= code: [[Code]] - code applied to each key-value pair - available variables:
<code>{ [[systemChat]] [[format]] ["%1", _forEachIndex]; } [[forEach]] [1,2,3]; {{cc|will return: "0", "1", "2" in [[systemChat]] messages}}</code> |EXAMPLE4=
* {{hl|[[Magic Variables#x|_x]]}}: key
* {{hl|[[Magic Variables#x|_y]]}}: value
* {{hl|[[Magic Variables#forEachIndex|_forEachIndex]]}}: iteration number


|x5= Iterating a [[HashMap]] [[_forEachIndex]]:
|p22= hashMap : [[HashMap]] - the HashMap to iterate over
<code>{ [[systemChat]] [[format]] ["%1-%2", _x, _y]; } [[forEach]] createHashMapFromArray [[1,"a"], [2,"b"]]; {{cc|will return: "1-a", "2-b" in [[systemChat]] messages}}</code> |EXAMPLE5=
____________________________________________________________________________________________


| [[set]], [[resize]], [[pushBack]], [[pushBackUnique]], [[apply]], [[reverse]], [[select]], [[in]], [[find]], [[findIf]], [[toArray]], [[toString]], [[count]], [[deleteAt]], [[deleteRange]], [[append]], [[sort]], [[param]], [[params]], [[arrayIntersect]], [[Control Structures]], [[splitString]], [[joinString]] |SEEALSO=
|r2= [[Anything]] - will return the value of last executed statement
}}


<h3 style="display:none">Notes</h3>
|x1= <sqf>
<dl class="command_description">
// SQF
<!-- Note Section BEGIN -->
{ _x setDamage 1 } forEach units player;
</sqf>
<sqs>
; SQS
"_x setDammage 1" forEach units player
</sqs>


<dd class="notedate">Posted on July 20, 2010
|x2= This command can also easily be used to execute a single command multiple times without respect to the array items - see also [[for]]
<dt class="note">[[User:Kronzky|Kronzky]]
<sqf>
<dd class="note">
{ player addMagazine "30Rnd_556x45_Stanag" } forEach [1, 2, 3, 4];
If arrays are used in forEach loops, _x uses them by reference, so any changes to _x will be applied to the original:
// equivalent to
<code>_arr1 = [1,2,3];
for "_i" from 1 to 4 do { player addMagazine "30Rnd_556x45_Stanag" };
_arr2 = [6,7,8];
</sqf>
{ [[_x]] [[set]] [1,"x"] } [[forEach]] [_arr1,_arr2];</code>
will change _arr1 to [1,"x",3], and _arr2 to [6,"x",8].
<!-- Note Section END -->
</dl>


<h3 style="display:none">Bottom Section</h3>
|x3= You can also use multiple commands in the same block:
[[Category:Scripting Commands|{{uc:{{PAGENAME}}}}]]
<sqf>
[[Category:Scripting Commands OFP 1.46|{{uc:{{PAGENAME}}}}]]
{
[[Category:Scripting Commands OFP 1.96|{{uc:{{PAGENAME}}}}]]
_x setCaptive true;
[[Category:Scripting Commands OFP 1.99|{{uc:{{PAGENAME}}}}]]
removeAllWeapons _x;
{{GameCategory|arma1|Scripting Commands}}
doStop _x;
[[Category:Scripting Commands Arma 2|{{uc:{{PAGENAME}}}}]]
} forEach units group this;
[[Category:Scripting Commands Arma 3|{{uc:{{PAGENAME}}}}]]
</sqf>
[[Category:Scripting Commands Take On Helicopters|{{uc:{{PAGENAME}}}}]]


<!-- CONTINUE Notes -->
|x4= To get the index of a [[forEach]] loop, use [[Magic Variables#forEachIndex|_forEachIndex]]:
<dl class="command_description">
<sqf>{ systemChat str _forEachIndex; } forEach ["a", "b", "c"]; // will return: "0", "1", "2" in systemChat messages</sqf>
<dd class="notedate">Posted on August 29, 2014 - 22:23 (UTC)</dd>
<dt class="note">[[User:Fett Li|Fett Li]]</dt>
<dd class="note">
[[forEach]] returns any (the last passed value will be the return value or just [[Nothing]], depends on the function called).
<code>_var = {_x} [[forEach]] [<nowiki/>[[nil]],"s",[[objNull]],[[configFile]] ]; {{cc|return bin\config.bin}}
_var = {_x [[setCaptive]] [[true]]} [[forEach]] [[allUnits]]; {{cc|return nothing}}</code>
</dd>


<dd class="notedate">Posted on September 20, 2014</dd>
|x5= Iterating a [[HashMap]]'s [[Magic Variables#forEachIndex|_forEachIndex]]:
<dt class="note">[[User:Mossarelli|Mossarelli]]</dt>
<sqf>
<dd class="note">
// shows "0, k1, v1", "1, k2, v2" in systemChat messages
Using the foreach loop, since there are no variable for the index like say the for-do loop, there is a variable that you can use to check the index of the foreach loop.
{
systemChat format ["%1, %2, %3", _forEachIndex, _x, _y];
} forEach createHashMapFromArray [
["k1", "v1"],
["k2", "v2"]
];
</sqf>


<code>{
|x6= [[findIf]] equivalent for [[HashMap]]:
[[if]] ([[_forEachIndex]] == 1) [[then]] {
<sqf>
// Copilot
private _resultKey = {
_x [[addUniform]] "U_B_Soldier_VR";
if (_y isEqualTo "wantedValue") exitWith { _x };
} [[else]] {
""
// Adams
} forEach _hashmap;
[_x, "B_Soldier_TL_F"] [[call]] [[BIS_fnc_loadInventory]];
</sqf>
_x [[addUniform]] "U_B_Soldier_VR";
_x [[setIdentity]] "Bootcamp_B_Adams";
};
} [[forEach]] _crew;
</code>
So when the array is past from _crew to the loop, index 1 (which is the second element) is the copilot of the "B_Heli_Light_01_F" and he will get "U_B_Soldier_VR" as a uniform. While the pilot which is index 0 (first element), will get the same uniform but will get the loadout of "B_Soldier_TL_F" and the identity of "Bootcamp_B_Adams".
</dd>


<dd class="notedate">Posted on January 2, 2015 - 22:35 (UTC)</dd>
|x7= Array is edited by reference:
<dt class="note">[[User:Heeeere's Johnny!|Heeeere's Johnny!]]</dt>
<sqf>
<dd class="note">
_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"]
</sqf>


Using [[exitWith]] inside a '''forEach''' loop will make '''forEach''' actually return something, namely whatever the '''exitWith''' returns:
|x8= <sqf>
<code>_result = {
{
    if(_x [[isEqualTo]] 3) [[exitWith]] {"Hello"}
private _verticalValue = _x; // needed, otherwise _horizontalValues' _x made this one inaccessible
} '''forEach''' [1,2,3,4,5];
{
//_result = "Hello"</code>
[_x, _verticalValue] call TAG_fnc_doSomething;
</dd>
} forEach _horizontalValues;
} forEach _verticalValues;
</sqf>


<dd class="notedate">Posted on November 28, 2017 - 13:46 (UTC)</dd>
|seealso= [[Control Structures]] [[for]] [[apply]] [[while]] [[select]] [[findIf]] [[count]] [[forEachReversed]]
<dt class="note">[[User:dedmen|dedmen]]</dt>
}}
<dd class="note">
 
Be careful when deleting ([[deleteAt]]) elements from an Array while you iterate over it.<br>
{{Note
|user= Dedmen
|timestamp= 20171128134600
|text= 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;
<sqf>
while {_forEachIndex < count _array} do {
private _forEachIndex = 0;
    (_array select _forEachIndex) call code;
while { _forEachIndex < count _array } do
    _forEachIndex = _forEachIndex + 1;
{
}</code>
(_array select _forEachIndex) call code;
_forEachIndex = _forEachIndex + 1;
};
</sqf>


So if you delete your current element from the array the other elements will shift forward. Meaning you skip one element.<br>
So if you delete your current element from the array the other elements will shift forward. Meaning you skip one element.<br>
Example:
Example:
<code>_array = [1,2,3,4,5,6];
<sqf>
{_array deleteAt _forEachIndex} forEach _array;
_array = [1,2,3,4,5,6];
</code>
{ _array deleteAt _forEachIndex } forEach _array;
</sqf>
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>
 
<!-- DISCONTINUE Notes -->
{{Note
|user= Sa-Matra
|timestamp= 20230402090428
|text= Use new [[forEachReversed]] command for deleting array items with [[deleteAt]]. Check its examples for details.
}}

Latest revision as of 20:58, 4 July 2024

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:
Game Logo A0.png1.00 Logo A1 black.png1.00 Logo A2.png1.00 A2 OA Logo.png1.50 Arma 3 logo black.png1.00 tkoh logo small.png1.00
String support Checked Unchecked
Code support Unchecked Checked

code: String only in Operation Flashpoint and Armed Assault, Logo A1 black.png1.00 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:
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 forEachReversed

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 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.
Sa-Matra - c
Posted on Apr 02, 2023 - 09:04 (UTC)
Use new forEachReversed command for deleting array items with deleteAt. Check its examples for details.