Concerns about function that checks if a given element is in an array

jaBote

Community Contributors
Messages
2,037
Points
0
Github
jaBote
Hi people.

I've recently seen other implementations of a function which just checks if a given value (numeric or string) is member on an array. It feels strange to me since I've always thought the best and most straight-forward way for doing that is via the implementation I've always done, which works for both numeric and string variables (please don't mind the .@i inicialization to 0, I know it's useless but it just does reassure me):

// Tries to find if a given element is inside a selected array// @params: element, array// @returns: 1 if found, 0 otherwisefunction in_array { .@total = getarraysize(getarg(1)); .@i = 0; while (.@i < .@total) { if (getarg(0) == getelementofarray(getarg(1),.@i)) { return 1; } .@i++; } return 0;}

But I've recently seen @@Winterfox's implementation in a request's topic (this one), which is a rather creative two-line implementation (disregarding the other lines):

function script PVPLP_revertLevel { setarray .@maps$, "izlude", "pvp2", "pvp3"; getmapxy( .@map$, .@x, .@y, 0 ); if( !compare( implode( .@maps$, ":" ), .@map$ ) ) end; atcommand "@blvl " + (PVPLP_TRUE_LEVEL - BaseLevel);}

Which makes me wonder about what one is more efficient and scalable. I guess Winterfox's implementation is somewhat faster (an implicit loop inside of implode and a string comparison is faster than a loop in which you compare elements one by one), but I've already used mine to find the index of the array which contains a given value (change return 1; to return i; and return 0; to return -1; (for not found) along with function's description (I named it array_pos, by the way).

P.S.: I guess it'd be a good idea if we made a suggestion for getting these functions (in_array and array_pos, whichever its implementation is) inside our repository? Implemented via source or as function, but we should also get repository public functions documented since no one I know makes use of them, or even gets them rewritten to make exactly_the_same_thing.

 
Last edited by a moderator:
@@jaBote

Upon reading it again i realized i could have made it even a bit shorter.

function script PVPLP_revertLevel { setarray .@maps$, "izlude", "pvp2", "pvp3"; if( !compare( implode( .@maps$, ":" ), strcharinfo( PC_MAP ) ) ) end; atcommand "@blvl " + (PVPLP_TRUE_LEVEL - BaseLevel);}
To the Topic:

A native in_array function would be a really great addition.

What also would be really good would be if getarraysize would return the real array size and not the highest index and a way to loop  trough a array via function instead of a index to make things like this possible:

... mes "There are " + getarraysize( .demoSpecialMobIds ) + " which currently give you a special bonus."; mes "These mobs are the following: "; while( .@mobId = next_element( .demoSpecialMobIds ) ) mes getmonsterinfo( .@mobId, MOB_NAME ); close;end;OnNPCKillEvent:if( !.demoSpecialMobIds[ killedrid ] ) end;... do some specialstuff for special mob ...end;OnInit: .demoSpecialMobIds[ 1000 ] = 1; .demoSpecialMobIds[ 1004 ] = 1; .demoSpecialMobIds[ 1006 ] = 1;end;...
I just realized that this ".array[ idIndex ]" approach is a workaround for a lacking in_array function especially for integers except you want to extensivly utilize atoi. The benefit is like the solution with implode, it may be better performance wise.

Maybe a in_array function could solve both cases to make it more readable at all.

A next_element or phplike foreach loop would still be great though.

Such a kind of function would be great for functions which should work with integer and string values. I could imagine things like this:

for( .@i = 0; .@i < getarraysize( getarg( 1 ) ); .@i++ ) mes getmonsterinfo( next_element( getarg( 0 ) ), next_element( getarg( 1 ) ) );
It would make it possible to either use the string constant or the number of specific informations to loop trough it via a function that doesn't care if it is a string or a number.

 
Last edited by a moderator:
'compare' was sometimes failure

for example:

xmas (players are at this map)
xmas_dun01 (in array)
xmas_dun02 (in array)

 
@@Angelmelody

That is correct, you need to use it with caution and this approach only is really usefull if you have to call that comparison a lot and / or the array is really big. Otherwise i think the performance benefit is really low.

 
@@jaBote

I guess the loop is faster and efficient than compare and implode.

 
@@Winterfox

it should be 

if( !compare( "#"+implode( .@maps$, "#" )+"#", "#"+strcharinfo( PC_MAP )+"#" ) ) end;
you should add the delimiter at the front and end of the string to get an accurate checking, which could fix the checking in Angelmelody post.

 
I prefer for loop w/o callfunction

Code:
.@arr_size = getarraysize(arraytetst);freeloop(.@arr_size > 510);for(.@i=0; arraytetst[.@i] != valtest ; .@i++ );freeloop(0);if(.@i  < .@arr_size )	mes " found!"else	mes "not found!";end;
 
Back
Top