Tutorial: Array Variables 5

From GECK

This is is the fifth and final part of a tutorial on NVSE Array Variables, which overviews the available functions related to them. The fourth part of the tutorial can be found here.

Sorting

Ar_Sort returns a new array with the values of the old one sorted in a specific order. This can only be done if they're all the same type (numbers, objects or strings), or it'll just return an empty array. Strings are sort alphabetically, numbers numerically, and forms according to their formID. The resulting array is a 'regular' array, no matter what the array to sort was:

let array2 := ar_sort array1 descendingSortBool        
    ; * if you don't specify that bool, it'll be in ascending order

Ar_SortAlpha does something similar, but the values don't have to be the same type - they're all converted to strings as if you used ToString and sorted alphabetically: strings stay strings, numbers become string representations of numbers, forms become their names if they have them (otherwise, it's their FormID strings).

let array2 := ar_sortalpha array1 descendingSortBool

If you need some more specific sorting, you can use Ar_CustomSort, for which you need to write a UDF. Ar_CustomSort will repeatedly take 2 elements from the array to sort, and pass them to the UDF as parameters in the form of arrays. Your UDF determines how the values of the 2 array var parameters should be sorted in relation to each other. This looks to be especially handy if you're sorting forms according to anything other than their name/formID (eg weight, size, skills etc), or sub-arrays. You let the function know that one element should be considered 'earlier than' or 'less than' in the resulting array's order by letting the UDF return 'true', ie: setting a function value.

let array2 := ar_customsort array1 SortingUDF descendingSortbool

Let's try this out, ok? I want to sort a bunch of Goodsprings residents according to their medicine skill, with those with higher skill earlier in the array, ie 'less than'.

scn MyComparisonUDF
    
array_var a       ; parameters
array_var b
ref rA            ; local ref vars
ref rB

Begin Function {a b}
    let rA := a[0]
    let rB := b[0]
    if rA.GetAV Medicine > rB.GetAV Medicine
        SetFunctionValue 1   
        ; * SetFunctionValue anyInt marks the comparison as returning: 
        ; * element value a < element value b
    endif
End
scn MyCallingScript
    
array_var array1
array_var array2
    
let array1 := ar_List TrudyRef, SunnyRef, DocMitchellRef, EasyPeteRef, GSJoeCobbRef, GSChetRef
let array2 := ar_CustomSort array1, MyComparisonUDF

Now array2 is a regular array sorted like in ascending order, which in our case means in descending order of medicine skill:

    0    DocMitchellRef    ; Doc has 33 medicine
    1    GSChetRef         ; Chet has 15
    2    TrudyRef          ; all these have 12
    3    SunnyRef
    4    EasyPeteRef
    5    GSJoeCobbRef      ; Joe Cobb has 10

If I use the Ar_CustomSort function with the descendingbool, it'll sort the array in descending order, which in our case means in ascending order of medicine skill:

    0    GSJoeCobbRef
    1    EasyPeteRef
    2    SunnyRef
    3    TrudyRef
    4    GSChetRef
    5    DocMitchellRef    

Regular Array Only Functions

As said a number of times already, regular arrays can only have positive, consecutive ints as keys, starting at 0. This is a limitation, but also something of a blessing because we can automate some things that way, which we can't do with maps and stringmaps.

Ar_Append, for instance, adds an element to an array at the next available key number.

Ar_append ArrayVar ValueToAdd.

Which is the same as:

let SomeInt := ar_size ArrayVar
let arrayVar[SomeInt] := ValueToAdd

If we had to do this with maps and stringmaps, and had no clue which keys they already had, we'd have to pick a random key, check whether the (string)map already had it with Ar_HasKey and only then add it or not, picking another. Or use Ar_Last and add something to that to create a new key.

Ar_Insert adds a value to an array at a key number that you specify, shifting up the one that's already there, as well as those with a higher key. You can also Ar_Insert to the total size of the array, in fact doing the same like Ar_Append. You can't insert at an index higher than the total size though, because you'd be missing a piece.

ar_insert ArrayToAddToVar KeyToAddAt ValueToAdd

let array1 := ar_list "value1", "value2", "value3", "value4"

ar_insert array1 2 "value2.5"

Will be:

    0  "value1"
    1  "value2"
    2  "value2.5"
    3  "value3"
    4  "value4"

Ar_InsertRange takes that one step further, and lets you insert a range of values in the middle or at the end of an array. You specify the range as yet another array.

Ar_InsertRange ArrayToAddToVar, KeyToStartAddingAt, ArrayToAddVar

So this is where we pick up our earlier example, adding array2 to the end of array1:

let array1 := ar_list value1, value2, value3, value4, ... value20
let array2 := ar_list value1, value2, value3, value4, ... value20   
 ; * who knows what value types and how many?
    
let iSize := ar_size array1               
ar_InsertRange array1 iSize array2
 ; * you could also just do: ar_InsertRange array1 (ar_size array1) array2

Will produce:

    0    value1fromarray1
    ...
    39    value20fromarray2
    if there were 20 each.

Finally, Ar_Resize lets you cut an array down to a size you specify, or expand it to a size you specify.

Ar_Resize ArrayToResizeVar, NewSizeInt, PaddingMulti(opt)

Wait, what's a paddingMulti? Well, a Multi is an array element value - could be whatever. So with 'paddingMulti", we mean any given value that you want the new values to be if you're scaling the array up. They're padding.

let arrayVar := Ar_Range 1, 20           
;--> creates a regular array with 20 elements, with the ints from 1-20 as values, and obviously the keys being 0-19

ar_resize arrayVar 5                    
;--> our array now only has 5 elements, with the ints 1-5 as values, and the keys being 0-4

ar_resize arrayVar 10 "SomeString"        
;--> our array now has 15 elements, with the keys 0-9, the first 5 values being 1-5, and the last 5 having "SomeString" as a value

Ar_Insert, Ar_InsertRange, and Ar_Resize all modify an array in place, and return a bool that tells you if they've done their jobs - if you want, you can check that in the same line as commanding them to do it:

if ar_resize arrayVar 10 "SomeString"
    ; It was successful
endif

Typically you probably won't need to bother checking it though.


That is all for this tutorial, see the relevant functions' pages for more information.


External Links

Personal tools