Array manipulation functions

meko

Core Developers
Messages
363
Points
0
IRC Nickname
meko
Github
Helianthella
Emulator
Hercules
Client Version
ManaPlus







View File

Array manipulation functions




This script provides various array manipulation functions, and more might be added in the future.
All of those functions (except the arithmetic ones) work with both integer and string arrays.

The start of the array is always implicitly index 0, unless an index is specified, ie @array[index]



array_pad(<array>, <size>, <value>)
pads the array left or right with <value> until it reaches <size> size. If <size> is negative it will pad left.
> returns the number of added entries

setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_pad(.@foo, 8, 69); // => 3

// array is now: 1, 2, 3, 4, 5, 69, 69, 69

Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_pad(.@foo, -8, 69); // => 3

// array is now: 69, 69, 69, 1, 2, 3, 4, 5




array_replace(<array>, <needle>, <replacement>{, <neq>})
finds every occurrence of <needle> within the array and replaces it with <replacement>. if <neq> is true, finds entries that do not match instead
> returns the number of changed entries
Code:
setarray(.@foo, 1, 1, 3, 1, 5); // initialize the array
array_replace(.@foo, 1, 69); // => 3

// array is now: 69, 69, 3, 69, 5
array_find(<array>, <needle>{, <neq>})
finds the first occurrence of <needle> within the array. if <neq> is true, finds entries that do not match instead
> returns the index, or if none is found returns -1
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_find(.@foo, 3); // => 2
array_find(.@foo, 1); // => 0
array_find(.@foo, 6); // => -1
array_rfind(<array>, <needle>{, <neq>})
like array_find, but finds the last occurrence. if <neq> is true, finds entries that do not match instead
> returns the index, or if none is found returns -1
Code:
setarray(.@foo, 1, 2, 3, 4, 3); // initialize the array
array_rfind(.@foo, 3); // => 4
array_rfind(.@foo, 4); // => 3
array_rfind(.@foo, 6); // => -1
array_exists(<array>, <needle>{, <neq>})
very similar to array_find() but it instead just checks if it exists or not. if <neq> is true, finds entries that do not match instead
> returns true or false
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_exists(.@foo, 3); // => true
array_exists(.@foo, 6); // => false
array_count(<array>, <needle>{, <neq>})
similar to array_find() but iterates through the whole array. if <neq> is true, finds entries that do not match instead
> returns the total number of occurrences of <needle>
Code:
setarray(.@foo, 1, 69, 3, 69, 5); // initialize the array
array_count(.@foo, 69); // => 2
array_entries(<array>)
a wrapper around array_count(). behaves similarly to getaraysize() but does not count holes
> returns the number of non-empty entries
Code:
setarray(.@foo, 1, 2, 0, 0, 5); // initialize the array
getarraysize(.@foo); // => 5
array_entries(.@foo); // => 3
array_remove(<array>, <needle>{, <neq>})
finds and removes every occurrence of <needle> from the array, while shifting left. if <neq> is true, finds entries that do not match instead
> returns the number of removed entries
Code:
setarray(.@foo, 1, 69, 3, 69, 5); // initialize the array
array_remove(.@foo, 69); // => 2

// array is now: 1, 3, 5
array_reverse(<array>)
reverses the array
> returns true
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_reverse(.@foo); // => true

// array is now: 5, 4, 3, 2, 1
array_sum(<array>)
iterates through the whole array to perform an arithmetic addition
> returns the sum of every entries of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_sum(.@foo); // ((((1 + 2) + 3) + 4) + 5) => 15
array_difference(<array>)
iterates through the whole array to perform an arithmetic subtraction
> returns the difference of every entries of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_difference(.@foo); // ((((1 - 2) - 3) - 4) - 5) => -13
array_product(<array>)
iterates through the whole array to perform an arithmetic multiplication
> returns the product of every entries of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_product(.@foo); // ((((1 * 2) * 3) * 4) * 5) => 120
array_quotient(<array>)
iterates through the whole array to perform an arithmetic division
> returns the quotient of every entries of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_quotient(.@foo); // ((((1 / 2) / 3) / 4) / 5) => 0
array_shift(<array>)
removes the first entry of the array, while shifting left
> returns the value of the removed entry
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_shift(.@foo); // => 1

// array is now: 2, 3, 4, 5
array_unshift(<array>, <value>)
adds <value> to the start of the array, while shifting right
> returns the new size of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_unshift(.@foo, 69); // => 6

// array is now: 69, 1, 2, 3, 4, 5
array_pop(<array>)
removes the last entry of the array
> returns the value of the removed entry
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_pop(.@foo); // => 5

// array is now: 1, 2, 3, 4
array_push(<array>, <value>)
adds <value> to the end of the array
> returns the new size of the array
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_push(.@foo, 69); // => 6

// array is now: 1, 2, 3, 4, 5, 69
array_shuffle(<array>)
shuffles the array
> returns true
Code:
setarray(.@foo, 1, 2, 3, 4, 5); // initialize the array
array_shuffle(.@foo); // => true

// array is now: 1, 4, 2, 3, 5 (example, unpredictable)




array_unique(<array>{, <threshold>})
allows array entries to appear up to <threshold> times (1 by default) and removes the extraneous ones. useful to remove duplicate entries
> returns the number of removed entries

setarray(.@foo, 1, 3, 3, 4, 5); // initialize the array
array_unique(.@foo); // => 1

// array is now: 1, 3, 4, 5





array_diff(<base array>, <array>{, <array>...}, <result array>)
compares the base array against one or more other arrays and fills the result array with the entries in base array that are not present in any of the other arrays
> returns the number of entries not found in other arrays

setarray(.@base, 1, 2, 3, 4, 5, 6, 7, 8); // initialize the base array

// fill the arrays to compare with the base array:
setarray(.@foo, 2, 3, 4, 5, 6, 7, 8); // missing "1"
setarray(.@bar, 1, 2, 3, 4, 6, 7, 8); // missing "5"
setarray(.@baz, 1, 2, 3, 4, 5, 6, 7); // missing "8"

// compare foo, bar and baz against base, and fill result:
array_diff(.@base, .@foo, .@bar, .@baz, .@result); // => 3

// .@result is now: 1, 5, 8





array_filter(<array>, "<function>")
filters the array using a function that is tested against every entries. if the function returns false, the relevant entry is removed and the array is shifted left
> returns the number of removed entries

function script is_prime {
if (getarg(0) <= 1)
return false;

for (.@i = 2; .@i <= getarg(0) / 2; ++.@i)
if ((getarg(0) % .@i) == 0)
return false;

return true;
}

setarray(.@foo, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
array_filter(.@foo, "is_prime"); // => 9

// array is now: 2, 3, 5, 7, 11, 13





array_sort(<array>)
sorts the array in ascending order
> returns true

setarray(.@foo, 2, 1, 8, 4, 5, 7, 6, 3); // initialize the array
array_sort(.@foo); // => true

// array is now: 1, 2, 3, 4, 5, 6, 7, 8





array_rsort(<array>)
sorts the array in descending order
> returns true

setarray(.@foo, 2, 1, 8, 4, 5, 7, 6, 3); // initialize the array
array_rsort(.@foo); // => true

// array is now: 8, 7, 6, 5, 4, 3, 2, 1






Requires Hercules of June 24 2017 or newer version
--------------------------------------------------------------------------------------

This script was made by me, for The Mana World + Evol.
L
icense: public domain (CC0)









 
Last edited by a moderator:
ohhhh ~ yesh algorithm script ~~~

not really sure about myself getting to use any of these, but the array_shuffle(<array>) makes me very interested :D

testing ....

EDIT : Oops ... I edited your script, sry ... it didn't throw error actually

http://upaste.me/5b17495746d1cbe0e

yup ~ a stable shuffle algorithm, gives 100 cases averagely each time

but do you know about the existence of Fisher-Yates shuffle ?

because if I understand your script correctly, you are using pencil and paper method



and how about ... ahem ~ ahem ~ the sorting algorithm function ... that you can sort an array

4,3,5,1,2 into 1,2,3,4,5 ?

PS: do a forum search "merge sort" or "counting sort" :innocent:

 
Last edited by a moderator:
@AnnieRuru I just released version 9, which adds array_filter() and makes array_shuffle() use the Durstenfeld implementation of the Fisher-Yates algorithm

 
:thumpsup:

thumbs-up.png


http://upaste.me/fa9a49576f63f6540

is there any explicit reason why you are using .@index and *getarrayindex ?

I play around a little bit and don't think it serve any .... meaning ?

 
all of the array functions take the given index into account, this means if you give array[8] it is only executed from index 8 onwards.

for array_shuffle this is not of much use but for array_shift, for example, it can be quite useful

consider an array that is 0, 1, 2, 3, 4 and that you want to remove 2: you would do array_shift(array[2]) and the array would become 0, 1, 3, 4

 
Last edited by a moderator:
for array_shuffle this is not of much use ...
omg .. I've used this quite a lot in my battleground scripts

to shuffle the array of the participants, to prevent players predicting they would join in which team

all of the array functions take the given index into account, this means if you give array[8] it is only executed from index 8 onwards.
:stumble: :o

never encounter a situation require this feature yet ~

but for array_shift, for example, it can be quite useful

consider an array that is 0, 1, 2, 3, 4 and that you want to remove 2: you would do array_shift(array[2]) and the array would become 0, 1, 3, 4
reminds me of my old mission board script ...

yeah, if I have known about these function, that script would have been much cleaner, rather than having for-loop over and over in that script

and I have fun playing with your scripts ~

maybe we can have another algorithm script discussion again some other time ~

 
released version 10, which adds array_sort() and array_rsort()

uses the Lomuto implementation of the Quicksort algorithm

works with both string arrays (arr$) and integer arrays (arr)

 
Last edited by a moderator:
http://upaste.me/542d49579ec44be6d

quick sort = 390~437 miliseconds (str & int)

comb sort = 312~344 miliseconds (str & int)

counting sort = 47~63 miliseconds (integer only)

comb sort still outperform quick sort or merge sort in hercules script engine

the reason is just like Haru said, *athena script engine parse function (for/while/goto) very slow, the more function it runs, the more slower it gets

and there is no need to use *strcmp script command

Code:
poring_w01,105,105,5    script    test string    1_F_MARIA,{
    dispbottom ( "test" == "test" ); // return 1
    dispbottom ( "123" > "321" ); // return 0
    dispbottom ( "asdf" < "qwer" ); // return 1
    end;
}
 
Last edited by a moderator:
@meko

Do you know how to create a function similar to sort/rsort, but it won't move a certain nth array?

E.g. #1, I have this array

setarray(.@Array,
4000, 3,
4001, 7,
4002, 1,
4003, 10,
4004, 0,
4005, 2);


Then I want to sort it so the left numbers (4000-4005) change position with the right no.

E.g. #2, now going to sort in ascending order.

4004, 0,
4002, 1,
4005, 2,
4000, 3,
4001, 7,
4003, 10,


As you can see, it only sorted every 2nd array, but it moved the preceding array with it.

Idk how to explain this. I think "anchor" would be the correct term. Value n determines how many values are anchored to the first array index before we sort by a new anchor. 

Hope it makes sense and hoping you can help me out.

Thanks.

 
Last edited by a moderator:
This is awesome. Please add more  :)

 
Last edited by a moderator:
@Smoke what kind of array function do you need?
Nothing that I personally need, these are just really helpful functions and are usually in any good library/framework.

 
how about array_len? for number of items? :)

would be great
There's already getarraysize() to get the highest index +1, but I guess what you seek is one that counts non-empty entries?

 
actually getarraysize(array) will suffize ^_^ .

ty you have been a great help

 
@andybe I just published version 7. See array_entries()

 
I would like to see an array_diff(.@array, .@array2)....

something like...

@array1[0] = 1, 2, 3;

@array2[0] = 1, 2, 3, 4, 5, 6, 7, 8, 9;

array_diff(@array1, @array2) = [ ]

array_diff(@array2, @array1) = [ 4, 5, 6, 7, 8 ]

First Array contains all items you WANT with any/all items from Second Array.... so in the first example with 1,2,3 it only checks against 1,2,3 existing in [1,2,3,4,5,6,7,8]

Where as in the second example it checks [ 1,2,3,4,5,6,7,8 ] for any or all occurrences of [1,2,3] and returns the ones that don't match.. [4,5,6,7,8 ]

 
Last edited by a moderator:
Back
Top