Good news! I have yet another donation from Andrey! Спасибо большое, Андрей, за поддержку!

I have recently came across BIS_fnc_arrayFindDeep, written sometime in 2006. Not sure what that function was supposed to do, but from the name it looks like the intention was to find a specified element in a nested array. The successful return of the function is in array format, so I assume it is to contain the path to the element. Let’s test it:

_arr = [1,2,[1,2,3,4,[1,2,3,4,5,6]]]; _res = [_arr,1] call BIS_fnc_arrayFindDeep; // [0] _res = [_arr,3] call BIS_fnc_arrayFindDeep; // -1 _res = [_arr,5] call BIS_fnc_arrayFindDeep; // -1 _res = [_arr,100] call BIS_fnc_arrayFindDeep; // -1

I pity all of you who included this function in their projects , as you can see it doesn’t work. If you used it to find elements in one dimensional array, then a single find command provides a much much better alternative. Basically what this function is, at the moment, is over-designed find method. So I got curious to try my hand at it.

// [<orig array>,<el to find>] call KK_fnc_findAll KK_fnc_findAll = { private ["_fnc","_tmp","_res","_lvl","_def"]; _fnc = { { if (isNil "_x") then { if (!_def) then { _tmp set [_lvl,_forEachIndex]; _res pushBack +_tmp; }; } else { if (typeName _x == "ARRAY") then { _tmp set [_lvl,_forEachIndex]; _lvl = _lvl + 1; _x call _fnc; _tmp resize _lvl; _lvl = _lvl - 1; } else { if (_def) then { if (_x isEqualTo _fnd) then { _tmp set [_lvl,_forEachIndex]; _res pushBack +_tmp; }; }; }; }; } forEach _this; }; _tmp = []; _res = []; _lvl = 0; _fnd = _this select 1; _def = !isNil "_fnd"; _this select 0 call _fnc; _res };

Unlike BIS_fnc_arrayFindDeep, KK_fnc_findAll will return paths for every match, no matter how deep it is buried inside multidimensional array. Of course the larger and deeper the array is, the longer the search will be. I feel this behaviour is more valuable than returning just the first match.

_arr = [1,2,[1,2,3,4,[1,2,3,4,5,6]]]; _res = [_arr,1] call KK_fnc_findAll; // [[0],[2,0],[2,4,0]] _res = [_arr,3] call KK_fnc_findAll; // [[2,2],[2,4,2]] _res = [_arr,5] call KK_fnc_findAll; // [[2,4,4]] _res = [_arr,100] call KK_fnc_findAll; // []

In order to retrieve found element later with the path, you can do it manually like this:

_arr = [1,2,[1,2,3,4,[1,2,3,4,5,6]]]; _res = [_arr,3] call KK_fnc_findAll; // [[2,2],[2,4,2]] _el = _arr select 2 select 4 select 2; // 2nd match [2,4,2] -> 3

Or, if you prefer…

// [<orig array>,<res path>] call KK_fnc_findAllGetPath KK_fnc_findAllGetPath = { private "_arr"; _arr = _this select 0; { _arr = _arr select _x; } forEach (_this select 1); if (isNil "_arr") then [{nil},{_arr}] };

Do it using a function:

_arr = [1,2,[1,2,3,4,[1,2,3,4,5,6]]]; _res = ([_arr,3] call KK_fnc_findAll) select 1; // 2nd match [2,4,2] _el = [_arr,_res] call KK_fnc_findAllGetPath; // -> 3

Did I mention that KK_fnc_findAll supports nil as well?

Enjoy,
KK

EDIT: Code now doesn’t throw undefined variable error when searching for or returning nil in scheduled environment, thanks to Gundy’s note.