Jump to content
Sign in to follow this  
terox

Function to search nested arrays

Recommended Posts

Am trying to make a function to search a nested array with 1 sub level of a set structure

I have a problem

the function output is [-1,-1]

it should be [2,0]

the function only searches through the first sub array then exits with the following variable values

_si = 3

_sn = 3

_i = 0

_n = 3

it never see's, or runs this line

{If (_Si == _Sn)then{_I = _i + 1;_si = 0; _sn = count (_array select _i)}

here is the debug format lines added to the function, that i used to ascertain what was happening

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE"> {If (_Si == _Sn)then{_i = _i + 1;_si = 0; _sn = count (_array select _i); player sidechat format ["Icounter _Si =%1 _Sn = %2 _i = %3 N= %4",_si,_sn,_i,_n]}

else

{_Si = _Si + 1; player sidechat format ["SIcounter _Si =%1 _Sn = %2 _i = %3 N= %4",_si,_sn,_i,_n]}

<span style='color:red'>INIT.SQS</span>

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">tx_searcharray = preprocessFile "fSubarrayGetIndex.sqf"

tx_array = [["a1","a2","a3"],["b1","b2","b3"],["c1","c2","c3"]]

~2

_e = ["c1",tx_array ]call tx_searcharray

hint format ["%1",_e]

<span style='color:red'>fSubarrayGetIndex.sqf</span>

_Sn count of Sub array

_Si index of sub array element

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

private ["_element", "_array", "_n", "_i", "_index", "_Sn", "_Si", "_Sindex"];

_element = _this select 0;

_array = _this select 1;

_n = count _array;

_i = 0;

_index = -1;

_Sindex = -1;

_Sn = count (_array select _i);

_Si = 0;

while "(_I < _n) && (_Si < _Sn)"

do

{

if (_element == ((_array select _i) select _si))then{_Sindex = _Si; _Index = _i; _i=N;_Si =_Sn}

else

{If (_Si == _Sn)then{_I = _i + 1;_si = 0; _sn = count (_array select _i)}

else

{_Si = _Si + 1}

};

};

_output = [_index,_Sindex];

player sidechat format ["%1",_output];

_output

thx in advance for any help offered

Share this post


Link to post
Share on other sites

Loop error:

Change:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">{If (_Si == _Sn)then{_I = _i + 1;_si = 0; _

to:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">{If ((_Si+1) == _Sn)then{_I = _i + 1;_si = 0; _

You're comparing an ordinal index to a cardinal count, hence the error.

Share this post


Link to post
Share on other sites

{Edited out first sentence - also, ColSandersLite beat me to it}

Here is something I whipped up... sorry if I don;t use the same code as you, but I like to start fresh on stuff like this to make sure I don't get stuck as you are.

I've also left the variables as full names for ease of understanding. You can simplify if needed.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">

private["_array", "_subarray","_value","_counter","_subcounter","_maxcounter","_submaxcounter","_returnindexarray","_foundvalue"];

_Array = _this select 0;

_Value = _this select 1;

_SubArray = [];

_Counter = 0;

_SubCounter = 0;

_MaxCounter=count _Array;

_SubMaxCounter=0;

_ReturnIndexArray=[-1,-1];

_FoundValue = false;

While {(_Counter<=_MaxCounter) && (!FoundValue)} do

{

    _SubArray = _Array select _Counter;

    If (_Value in _SubArray) then

    {

         _SubCounter = 0;

         _SubMaxCounter = count _SubArray;

         while {(_SubCounter < _SubMaxCounter) && (!FoundValue)} do

         {

              If (_SubArray select _SubCounter == _Value) then

              {

                   _ReturnIndexArray = [_Counter,_SubCounter];

                   _FoundValue = true;

              };

              _SubCounter =_SubCounter+1;

         }

    }

    _Counter=_Counter+1;

};

_ReturnIndexArray

Normally, I would suggest a recursive function, but OFP doesn't seem to like recursive functions... atleast the ones I had always bugged out on me (probably exceeded 4k chars - who knows?).

Therefore I wrote this which will return an array showing the Index of the subarray and the index of the element within the subarray.

By using "in" it should cut down on search time if the "in" keyword is truly faster than simply iterating through bluntly.

It will also exit once it finds the value - a good thing if it's the first value. The bad thing is that if it's the last value - it will take full length of time. There are methods to simplify that, but statistically it should all be the same anyways if your search is pretty random. Anyway... thats a whole 'nother topic.

Share this post


Link to post
Share on other sites

Also, I don't mean to seem like I'm ragging on you or anything but, the proper way to do a nested search is this:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">private ["_element", "_array", "_i", "_j", "_indexA", "_indexB", "_numberOfA", "_numberOfB"];

_element = _this select 0;

_array = _this select 1;

_indexA = -1;

_indexB = -1;

_numberOfA = count _array;

_numberOfB = count (_array select 0);

_i = 0;

while "(_i < _numberOfA)" do

{

_j = 0;

while "(_j < _numberOfB)" do

{

if(_element == ((_array select _i) select _j)) then

{

_indexB = _j;

_indexA = _i;

_i =_numberOfA;

_j =_numberOfB;

};

_j = _j + 1;

};

_i = _i + 1;

};

_output = [_indexA,_indexB];

_output

If you're going to nest, like nesting loops or if statement, be sure to indent them for readability.

If you're going to use one letter variable names as counters, they should be labeled i, j, k, (skip l as it look like an uppercase I), m, n, etc.

Also, variable name consistancy is important for readability.

Notice the way I do my indentation and brackets. My way is one of a few standard ways of doing this. Be sure to pick a method and consistantly use it.

While it may not matter in OFP, variable names should have consistant capitalization. In most programming languages, this is important, as "myvariable" would be different from "myVariable" and this causes errors. Us programmers tend to red flag things like that, just because we're used to doing it.

You should pick a capitalization scheme and stick with it. The most common is "camel notation", which is the first letter lowercase, and the first letter of every word uppercase, like this: "thisIsMyVariable". This will aid readability, and will help you if you ever branch out of ofp scripts.

Ohh, and I can't stress this enough:

Consistancy!

CrashDome's method is a little bulkier, but is still correct. There's nothing wrong with a little bulk as long as it's easy to follow. Especially when it's consistant.

Share this post


Link to post
Share on other sites
Notice the way I do my indentation and brackets.  My way is one of a few standard ways of doing this.  Be sure to pick a method and consistantly use it.

While it may not matter in OFP, variable names should have consistant capitalization.  In most programming languages, this is important, as "myvariable" would be different from "myVariable" and this causes errors.  Us programmers tend to red flag things like that, just because we're used to doing it.

You should pick a capitalization scheme and stick with it.  The most common is "camel notation", which is the first letter lowercase, and the first letter of every word uppercase, like this: "thisIsMyVariable".  This will aid readability, and will help you if you ever branch out of ofp scripts.

Ohh, and I can't stress this enough:

Consistancy!

CrashDome's method is a little bulkier, but is still correct.  There's nothing wrong with a little bulk as long as it's easy to follow.  Especially when it's consistant.

I wish more people used brackets like yourself. I cannot stand the ..

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">If (xxx) then {

    /// do something

}

That first bracket alway gets lost for me. When there's alot of code I just like to scroll straight up and find the matching bracket.

I also try to use consistant variable names but I sure don't most of the time. I tend to use a mix depending on scope.

camel for private variables

pascal for Public

This is a carryover from what I do everyday - only difference is it's harder to carryover into OFP because the language is so different tounge2.gif which is why I am terrible in following my own practices.

Also, my code may be bulkier, but your example would search the entire array and sub-array even if the value was the first element whereas mine would exit the function wink_o.gif

Share this post


Link to post
Share on other sites
This is a carryover from what I do everyday - only difference is it's harder to carryover into OFP because the language is so different tounge2.gif which is why I am terrible in following my own practices.

Also, my code may be bulkier, but your example would search the entire array and sub-array even if the value was the first element whereas mine would exit the function wink_o.gif

Well no, my code does exit when it find the searched for item by setting i and j to the last members of the array when it finds what it looks for.

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE"> _i =_numberOfA;

_j =_numberOfB;

Anyways, it's always nice to meet another programmer. thumbs-up.gif

Share this post


Link to post
Share on other sites

thanks a lot for your help folks

advice greatly appreciated.

As you can see, i'm no professional programmer, am in RL a gas fitter and only took up coding about 6 months after OFP was launched.

So the standard i am at now, is all self taught

any advice that improves my coding is warmly accepted

I dont understand what you mean by "Recursive function"

Share this post


Link to post
Share on other sites

Recursive means that the function calls itself. The advantage of this method is, that it doesn't change anything how many levels you have in your array.

You can search an array like

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">[0,1,[2,3],[[4,5],[6,7]]]

and still the value will be found.

Here is the function that you need for it. Note that it's important that this function is saved in the public variable fArrayDeepFind

fArrayDeepFind.sqf

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">private["_c","_i","_r","_v","_a"];

_a=_this select 0;

_v=_this select 1;

_r=-1;

_i=0; _c=count _a;

while {_i<_c && _r in [-1]} do

{

if not ((_a select _i) in [_a select _i]) then

{

_r=[_a select _i,_v] call fArrayDeepFind;

if not (_r in [-1]) then

{

_r=[_i]+_r;

}else{

_i=_i+1;

};

}else{

if call format["{%1}=={%2}",_v,_a select _i] then

{

_r=[_i];

}else{

_i=_i+1;

};

};

};

_r

Let's have an example with our above array:

<table border="0" align="center" width="95%" cellpadding="0" cellspacing="0"><tr><td>Code Sample </td></tr><tr><td id="CODE">_array = [0,1,[2,3],[[4,5],[6,7]]]

[_array, 1] call fArrayDeepFind

; => [1]

[_array, 2] call fArrayDeepFind

; => [2,0]

[_array, 6] call fArrayDeepFind

; => [3,1,0]

Edit: Unfortunately tabs or spaces don't work in the code blocks, so I recommend you to indent the function blocks yourself to get a better understanding of it.

Edit 2: If you know how many levels the to-be-searched arrays have, it is better to use one fixed function with a certain number of nested whiles, because you don't need to check every value if it's an array or not then.

Share this post


Link to post
Share on other sites
Quote[/b] ]If you know how many levels the to-be-searched arrays have, it is better to use one fixed function with a certain number of nested whiles, because you don't need to check every value if it's an array or not then.

yeah but if it is insignificant speed-wise, why? it allows for easier manipulation to implement different search patterns and easier to read code ...but it's also a matter of taste. wink_o.gif

I like it because it is more organized - and despite how my code often looks I am an organizational nut. The fact that my mind likes to blast full speed ahead while coming up with programming solutions tends to supercede the organizational part. smile_o.gif

[Edit] Terox,... I am tempted to recommend you use hardrocks function. It's a bit overkill maybe, but you'll always have it and like an array multi-tool it will be your trusty friend for most occasions. The only thing is , and I will admit I am not 100% sure.. is recursive functions seem not to work well for me... but it could simply be me!

Share this post


Link to post
Share on other sites
yeah but if it is insignificant speed-wise, why?

Well, depending on the usage it may impact more or less on the performance. Of course, if you search an array five times a mission, it will do fine like that. It does make a difference with looping scripts running multiple times at once though, I guess.

Share this post


Link to post
Share on other sites

this thread turned into something else didnt it.

Thx a lot for all the help and explanations guys, much appreciated

Thanks for the recursive multi dimension search function.

For my current needs, its not needed, however now that i have it, it will certainly be used for other projects.

Share this post


Link to post
Share on other sites
this thread turned into something else didnt it.

Well no, it still deals with finding the most efficient way to search values in nested arrays. wink_o.gif

The good thing about the function I posted is, that you don't need to change it when you decide to change the way the array is built. With loops you have to adjust the function, but with the recursive function the call still remains the same.

Share this post


Link to post
Share on other sites
With loops you have to adjust the function, but with the recursive function the call still remains the same.

True. But I have to admit that personally, I hate to use anything recursive in an interpreted scripting language.

I do use recursion to their full extent in OOPLs and in database design though.

Maybe that's just me, but there you have it.

Share this post


Link to post
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
Sign in to follow this  

×