Difference between revisions of "Introduction to OBSE arrays"

From the Oblivion ConstructionSet Wiki
Jump to navigation Jump to search
imported>QQuix
m (Fixed a typo)
imported>Syscrusher
m (→‎Some final, miscellaneous notes: Punctuation correction)
 
(3 intermediate revisions by 2 users not shown)
Line 1: Line 1:
__NOTOC__
 
====Foreword====
====Foreword====
This article presents the basics of OBSE arrays.  
This article presents the basics of OBSE arrays.  
Line 169: Line 169:
::When initializing an array with ar_Construct, the type of array must be provided as the argument:
::When initializing an array with ar_Construct, the type of array must be provided as the argument:


<dl><dd><dl><dd>
:::let MyArray := ar_Construct array
let MyArray := ar_Construct array
:::let MyArray := ar_Construct map
let MyArray := ar_Construct map
:::let MyArray := ar_Construct stringmap
let MyArray := ar_Construct stringmap
</dl></dl>




2. Assigning the value of another array_var to it
2. Assigning the value of another array_var to it
:: In this case MyArray will be of the same type of SomeArray (actually, both refer to the same array)
:: In this case MyArray will be of the same type of SomeArray (actually, both refer to the same array)
<dl><dd><dl><dd>
let SomeArray := ar_Construct array
Let MyArray := SomeArray
</dl></dl>


:::let SomeArray := ar_Construct array
:::Let MyArray := SomeArray


3. Assigning it the return value of a command returning an array such as GetItems.
<dl><dd><dl><dd>
Let MyArray := GetItems
</dl></dl>




3. Assigning it the return value of a command returning an array such as GetItems.
::Let MyArray := GetItems


==Populating arrays==
==Populating arrays==
Line 198: Line 192:
The keys, of course, must comply with the type of array:
The keys, of course, must comply with the type of array:


<dl><dd><dl><dd>
let MyArray := ar_Construct array
Let MyArray[0] := 123
Let MyArray[1] := 456
Let MyArray[2] := 789
</dl></dl>


<dl><dd><dl><dd>
::let MyArray := ar_Construct array
let MyArray := ar_Construct map
::Let MyArray[0] := 123
Let MyArray[-1.5] := 123
::Let MyArray[1] := 456
Let MyArray[2.5] := 456
::Let MyArray[2] := 789
Let MyArray[3] := 789
 
</dl></dl>
 
::let MyArray := ar_Construct map
<dl><dd><dl><dd>
::Let MyArray[-1.5] := 123
let MyArray := ar_Construct stringmap
::Let MyArray[2.5] := 456
Let MyArray["Cost"] := 123
::Let MyArray[3] := 789
Let MyArray["Qty"] := 456
 
Let MyArray["Taxes"] := 789
 
</dl></dl>
::let MyArray := ar_Construct stringmap
::Let MyArray["Cost"] := 123
::Let MyArray["Qty"] := 456
::Let MyArray["Taxes"] := 789




Line 226: Line 217:
The [[Let]] statement is array-aware and is the most common way of accessing array elements
The [[Let]] statement is array-aware and is the most common way of accessing array elements


<dl><dd><dl><dd>
 
float MyFloat
::float MyFloat
. . .
::. . .
Let MyFloat := MyArray["PosX"]  
::Let MyFloat := MyArray["PosX"]  
Player.setpos x MyFloat
::Player.setpos x MyFloat
</dl></dl>
 
<dl><dd><dl><dd>
 
ref MyRef
::ref MyRef
. . .
::. . .
Let MyRef := MyArray["ReferenceID"]  
::Let MyRef := MyArray["ReferenceID"]  
MyRef.Kill
::MyRef.Kill
</dl></dl>
 
<dl><dd><dl><dd>
 
string_var MyString
::string_var MyString
. . .
::. . .
Let MyString := MyArray[3.7]
::Let MyString := MyArray[3.7]
MessageBoxEX "The element text is: %z" MyString
::MessageBoxEX "The element text is: %z" MyString
</dl></dl>




In all examples up to here, keys were explicitly coded, but they may also be in a variable and the variable itself going within the brackets:
In all examples up to here, keys were explicitly coded, but they may also be in a variable and the variable itself going within the brackets:


<dl><dd><dl><dd>
 
string_var MyString
::string_var MyString
. . .
::. . .
Let MyString := "Item value"
::Let MyString := "Item value"
Let MyArray[MyString] := 300
::Let MyArray[MyString] := 300
</dl></dl>
 
<dl><dd><dl><dd>
 
short MyShort
::short MyShort
. . .
::. . .
Let MyShort := 3
::Let MyShort := 3
Let MyArray[MyShort] := "Text"
::Let MyArray[MyShort] := "Text"
</dl></dl>




Line 275: Line 264:
ForEach loops iterate over the elements of an array.
ForEach loops iterate over the elements of an array.


<dl><dd><dl><dd>
 
array_var item
::array_var item
short MyShort
::short MyShort
string_var MyString
::string_var MyString
. . .
::. . .
ForEach item <- MyArray
::ForEach item <- MyArray
    Let MyShort := item["key"]
:::Let MyShort := item["key"]
    Let MyString := item["value"]
:::Let MyString := item["value"]
    MessageEX "The element %g  is: %z" MyShort MyString
:::MessageEX "The element %g  is: %z" MyShort MyString
Loop
::Loop
</dl></dl>
 


At each iteration, "item" is initialized with two elements:  
At each iteration, "item" is initialized with two elements:  
Line 302: Line 291:


The same example as above using a While loop:
The same example as above using a While loop:
<dl><dd><dl><dd>
 
short MyIndex
::short MyIndex
string_var MyString
::string_var MyString
. . .
::. . .
Let MyIndex := 0
::Let MyIndex := 0
While MyIndex < ar_size MyArray
::While MyIndex < ar_size MyArray
    Let MyString := MyArray[MyIndex]
:::Let MyString := MyArray[MyIndex]
    MessageEX "The element %g  is: %z" MyIndex MyString
:::MessageEX "The element %g  is: %z" MyIndex MyString
    MyIndex += 1
:::MyIndex += 1
Loop
::Loop
</dl></dl>
 


Notice that with while loops, you have to increase the index yourself, as opposed to ForEach loops that automatically go to the next element.
Notice that with while loops, you have to increase the index yourself, as opposed to ForEach loops that automatically go to the next element.
Line 318: Line 307:


A somewhat different (perhaps more elegant) way of increasing the index
A somewhat different (perhaps more elegant) way of increasing the index
<dl><dd><dl><dd>
 
short MyIndex
 
string_var MyString
::short MyIndex
. . .
::string_var MyString
Let MyIndex := -1
::. . .
While (MyIndex += 1) < ar_size MyArray
::Let MyIndex := -1
    Let MyString := MyArray[MyIndex]
::While (MyIndex += 1) < ar_size MyArray
    MessageEX "The element %g  is: %z" MyIndex MyString
:::Let MyString := MyArray[MyIndex]
Loop
:::MessageEX "The element %g  is: %z" MyIndex MyString
</dl></dl>
::Loop
 




While loops also allows for walking Arrays backward:
While loops also allows for walking Arrays backward:
<dl><dd><dl><dd>
 
short MyIndex
 
string_var MyString
::short MyIndex
. . .
::string_var MyString
Let MyIndex := ar_size MyArray
::. . .
While (MyIndex -= 1) >= 0
::Let MyIndex := ar_size MyArray
    Let MyString := MyArray[MyIndex]
::While (MyIndex -= 1) >= 0
    MessageEX "The element %g  is: %z" MyIndex MyString
:::Let MyString := MyArray[MyIndex]
Loop
:::MessageEX "The element %g  is: %z" MyIndex MyString
</dl></dl>
::Loop
 




Line 347: Line 338:
*References cannot be used as array keys.
*References cannot be used as array keys.
*An array can contain any mix of types for its values.
*An array can contain any mix of types for its values.
*As array elements may contain any type of data, it is the script responsibility to know which is which, so you don't try to assign a string to a ref variable.
*As array elements may contain any type of data, it is the script's responsibility to know which is which, so you don't try to assign a string to a ref variable.
*OBSE keeps track of the number of references to each array and destroys the array when no references to it remain. This makes it unnecessary for scripts to worry about destroying arrays explicitly.
*OBSE keeps track of the number of references to each array and destroys the array when no references to it remain. This makes it unnecessary for scripts to worry about destroying arrays explicitly.
*ForEach and While loops both define structured blocks in the same way that If and Endif or Begin and End do. Every While or ForEach in a script must be matched by exactly one Loop command.
*ForEach and While loops both define structured blocks in the same way that If and Endif or Begin and End do. Every While or ForEach in a script must be matched by exactly one Loop command.

Latest revision as of 21:30, 13 May 2014

Foreword[edit | edit source]

This article presents the basics of OBSE arrays. Much of the text comes straight from the OBSE docs.


Arrays[edit | edit source]

An array is a collection of related information put together in a list-like structure.

Being a list, an array may hold many values, as opposed to regular script variables that hold only one information.

Some examples of everyday lists that could be stored in arrays:


Shopping list Agenda Personal data
- Bread 08:30 - Sign in, Coffe Name: Adoring Fan
- Butter 09:00 - Introduction Date of birth: Morningstar 2, 415
- Milk 09:30 - Presentation A Age: 19
- Eggs 10:30 - Coffe break Address: Arena District, IC
11:00 - Presentation B Race: Wood Elf
ReferenceID: ArenaFan1ref


Array keys and values[edit | edit source]

Each element of the array is composed of a Key and a Value.

Key
The Key identifies the element and must be unique within an array.
An array key may be a number or a string, but all the keys in an array must be of the same type.
Arrays are ordered by key, in ascending order.
The key is represented within brackets, e.g., MyArray[0].
Value
Value is the information stored in the array element.
The value may be of any type: a string, a number, a FormID (base object or reference) or another array.
Any mix of value types may be stored in the same array.


Array types[edit | edit source]

There are three types of arrays, depending on the key used: Array, Map or StringMap.

Array[edit | edit source]

The "Array" type of array uses integers as keys.

The first element must have key = 0 and subsequent keys must be the next integer: 1, 2, 3, 4 etc.

There must be no gaps in the key sequence.

If an element is inserted or removed from the array, the keys are renumbered to comply with the above rules.

The Shopping List example would look like this when stored in an Array


Key Value
0 Bread
1 Butter
2 Milk
3 Eggs


Quote from the OBSE doc:
1. Array: An Array behaves like arrays in most programming languages: the key is an unsigned integer starting at zero, and there are no gaps between elements. (In other words, if an element exists at indexes 1 and 3 then an element necessarily exists at 0 and 2). Attempting to access an element using a key which is greater than the highest key in the array results in an error. The only exception to this rule is during assignment: it is okay to assign a value to the key which is one greater than the highest key in the array.


Map[edit | edit source]

The Map array uses numbers as keys.

Keys may be any number, including negative and floating point numbers

The Agenda example would look like this when stored in a Map array:


Key Value
8.5 Sign in, Coffe
9.0 Introduction
9.5 Presentation A
10.5 Coffe break
11.0 Presentation B
Quote from the OBSE doc:
2. Map: A Map associates numeric keys with values. Unlike an Array, a Map allows negative and floating point numbers to be used as keys and allows gaps to exist between elements.

StringMap[edit | edit source]

The StringMap array uses strings as keys.

The Personal Data example would look like this when stored in an StringMap array:


Key Value Value Type
Name Adoring Fan String
Date of birth Morningstar 2, 415 String
Age 19 Float
Address Arena District, IC String
Race Wood Elf Ref
ReferenceID ArenaFan1ref Ref


  • Note: Although only this last example has a mixture of value types, arrays of ANY type may have mixed value types.


Quote from the OBSE doc:
3. StringMap: Like a Map, except the keys are strings. Keys are case-insensitive, so array[INDEX] and array[index] both refer to the same value. There is no practical limit on the length of the strings used as keys. StringMaps can be used to simulate C-style structs by associating named properties with data values.


Declaring and initializing arrays[edit | edit source]

Arrays must be declared as an array_var variable, e.g., "array_var MyArray"

An array_var must be initialized before it can be used in expressions, either by


1. Explicitly initializing it using ar_Construct

When initializing an array with ar_Construct, the type of array must be provided as the argument:
let MyArray := ar_Construct array
let MyArray := ar_Construct map
let MyArray := ar_Construct stringmap


2. Assigning the value of another array_var to it

In this case MyArray will be of the same type of SomeArray (actually, both refer to the same array)
let SomeArray := ar_Construct array
Let MyArray := SomeArray


3. Assigning it the return value of a command returning an array such as GetItems.

Let MyArray := GetItems

Populating arrays[edit | edit source]

Arrays are populated by assigning values to its elements.

An array element is identified by the array name followed by the element key within brackets.

The keys, of course, must comply with the type of array:


let MyArray := ar_Construct array
Let MyArray[0] := 123
Let MyArray[1] := 456
Let MyArray[2] := 789


let MyArray := ar_Construct map
Let MyArray[-1.5] := 123
Let MyArray[2.5] := 456
Let MyArray[3] := 789


let MyArray := ar_Construct stringmap
Let MyArray["Cost"] := 123
Let MyArray["Qty"] := 456
Let MyArray["Taxes"] := 789


Accessing array elements[edit | edit source]

Using the data stored in arrays usually requires that you copy the information into a 'normal' script variable because array elements cannot be passed directly to most commands as arguments.


The Let statement is array-aware and is the most common way of accessing array elements


float MyFloat
. . .
Let MyFloat := MyArray["PosX"]
Player.setpos x MyFloat


ref MyRef
. . .
Let MyRef := MyArray["ReferenceID"]
MyRef.Kill


string_var MyString
. . .
Let MyString := MyArray[3.7]
MessageBoxEX "The element text is: %z" MyString


In all examples up to here, keys were explicitly coded, but they may also be in a variable and the variable itself going within the brackets:


string_var MyString
. . .
Let MyString := "Item value"
Let MyArray[MyString] := 300


short MyShort
. . .
Let MyShort := 3
Let MyArray[MyShort] := "Text"


Which is very handy to . . .


Walking an array[edit | edit source]

Walking an array means going over each element of the array, one at a time.

OBSE provides functions to do exactly that: ForEach and While loops


ForEach[edit | edit source]

ForEach loops iterate over the elements of an array.


array_var item
short MyShort
string_var MyString
. . .
ForEach item <- MyArray
Let MyShort := item["key"]
Let MyString := item["value"]
MessageEX "The element %g is: %z" MyShort MyString
Loop


At each iteration, "item" is initialized with two elements:

  • "key", which holds the key of the current element
  • "value", which holds the value associated with that key

Therefore, as in the example above, within a ForEach loop you can access both fields via item["key"] and item["value"].


NOTE: In the example, the key is copied to a Short, which implies that MyArray is either an Array or a Map that has only integers as keys.


While[edit | edit source]

While loops are handy for handling Arrays because the keys are known in advance and are consecutive (0,1,2,3, ...)


The same example as above using a While loop:

short MyIndex
string_var MyString
. . .
Let MyIndex := 0
While MyIndex < ar_size MyArray
Let MyString := MyArray[MyIndex]
MessageEX "The element %g is: %z" MyIndex MyString
MyIndex += 1
Loop


Notice that with while loops, you have to increase the index yourself, as opposed to ForEach loops that automatically go to the next element.


A somewhat different (perhaps more elegant) way of increasing the index


short MyIndex
string_var MyString
. . .
Let MyIndex := -1
While (MyIndex += 1) < ar_size MyArray
Let MyString := MyArray[MyIndex]
MessageEX "The element %g is: %z" MyIndex MyString
Loop


While loops also allows for walking Arrays backward:


short MyIndex
string_var MyString
. . .
Let MyIndex := ar_size MyArray
While (MyIndex -= 1) >= 0
Let MyString := MyArray[MyIndex]
MessageEX "The element %g is: %z" MyIndex MyString
Loop


Some final, miscellaneous notes[edit | edit source]

  • All elements within an array must have the same type of key.
  • References cannot be used as array keys.
  • An array can contain any mix of types for its values.
  • As array elements may contain any type of data, it is the script's responsibility to know which is which, so you don't try to assign a string to a ref variable.
  • OBSE keeps track of the number of references to each array and destroys the array when no references to it remain. This makes it unnecessary for scripts to worry about destroying arrays explicitly.
  • ForEach and While loops both define structured blocks in the same way that If and Endif or Begin and End do. Every While or ForEach in a script must be matched by exactly one Loop command.
  • Category:Array Functions (OBSE) has a list of OBSE array functions.