List
Instead of arrays,
LSL uses
lists. The list
type is exactly what it sounds like: a heterogeneous list of the other data types. Lists are created via
comma-separated values (CSV) of the other data types. enclosed by square brackets: "[" and "]". See below for examples of the
syntax.
Lists not only store the
value of the list item, but also its type (see
llGetListEntryType and
llCSV2List). To directly enter a
float value into a list, a decimal point (.) must be used.
Because they store multiple value types, lists are not accessed with square brackets like arrays are. They are read by accessor
functions that specify the type of value attempting to be retrieved (e.g.
llList2Integer) and written with accessor functions that insert or replace values (or ranges of values) based on new list
variables (e.g.
llListReplaceList).
Note: while the
LSL compiler will only accept
code with a maximum of 72 items in a list, lists can actually support as many items as a
script's memory will allow. If a list of more than 72 predefined items is needed, just
concatenate (combine) two predefined lists into a new one:
longlist = firstpart + secondpart;
Lists cannot contain other lists, so using them like a multidimensional array is not possible natively (although several ways around this are available, notably
this script). Also,
strided lists can be used.
Example:
//a list with a string, integer, float, vector and rotation
list l = ["somestring",12,3.0,<3.3,4,0>,<0,0,0,1>];
Lists can be
concatenated by using
+.
Example:
newlist = oldlist + ["oneitem","anotheritem"];
Thus, to
add an element to the (end) of an existing list:
Example:
myList = myList + [new_item];
or
myList += [new_item];
This voodoo magic will allow appending new elements in a memory efficient fashion (thanks to
BlindWanderer):
myList = (myList=[]) + myList + ["new_item"];
Don't ask me why but I can save 3-4KB of memory with adding 90 elements. -
PsykePhaeton
Is this broken as of Aug-21-2007? It doesn't appear to work -
VagnerSousaBR "This voodoo magic seems to work fine. Just pay attention to the "new_item" square brackets when it's already returned as a list type in a function like llParseString2List(). I got a stack-heap collision error when I was composing an huge list by the usual way. This way has worked fine."
To clear a list, set it equal to nothing:
Example:
To search a list for a value, use
llListFindList
list myList = ["A","B","C","D","E","F"];
string searchFor = "C";
integer index = llListFindList( myList, [searchFor] );
if ( index != -1 )
llOwnerSay( searchFor + " was found in myList at position " + (string)index );
else
llOwnerSay( searchFor + " was not found in myList" );
Refer to a list's elements by their index number. Lists have 0-based indexing, where the first element has index 0.
Example:
list myList = ["A","B","C"];
string element;
element = llList2String(myList,0);
// element now has the value "A".
element = llList2String(myList,1);
// element now has the value "B".
element = llList2String(myList,2);
// element now has the value "C".
The value
llGetListLength() returns the number of elements in the list. Therefore, the last element has
index = (llGetListLength(myList) - 1).
Example:
list myList = ["A","B","C"];
integer listLength = llGetListLength(myList);
// listLength equals 3.
string element = llList2String(myList,listLength);
// myList doesnt have an element at index 3 - this will return an empty string.
string element = llList2String(myList,listLength - 1);
// element now has the value "C".
Negative numbers can also be used to count backwards in a list. Therefore, the last element has
index -1. The first element would also have an index of (
-llGetListLength(myList))
Example:
list myList = ["A","B","C"];
integer listLength = llGetListLength(myList);
// listLength equals 3.
string element = llList2String(myList,-listLength);
// element now has the value "A".
string element = llList2String(myList,-1);
// element now has the value "C".
Functions
Strided Lists
Since lists cannot contain items of the list type, the only way to get something similar to a multidimensional array is using strides. A strided list is a regular list with items grouped together in a fixed layout.
Say you wanted to make a visitor tracker and keep track of visitor's names, time spent on your
land, and the date they visited last. You'd use a strided list, where each stride consists of three items:
integer STRIDELENGTH = 3; // this is very helpful when dealing with strided lists to keep your code flexible
list visitors = ["Ama Omega", 5, "2004-06-12", "Catherine Omega", 12, "2004-06-28", "Ezhar Fairlight", 25, "2004-06-30"];
//
Whenever you manipulate this list, you do it in complete strides, so to add another visitor to the list:
visitors += ["Mistress Midnight", 1, "2004-06-30"];
To sort the list by names in ascending order:
To remove one stride from the list:
list DeleteSubListStrided(list src, integer start, integer end, integer stride) {
return llDeleteSubList(src, start * stride, (end * stride) + stride - 1);
}
visitors = DeleteSubListStrided(visitors, 0, 0, STRIDELENGTH);
To replace a stride in the list:
list UpdateSubListStrided(list src, list stride, integer start, integer len) {
return llListReplaceList(src, stride, start, len-1);
}
The following functions have direct support for strided lists:
More examples of functions dealing with strided lists can be found on this page.
LibraryStridedLists
Q & A
Q: Does this function have O(1) time? I want to use it a lot on some big lists.
A: No, it takes much longer with growing list size. Better get used to LSL being painfully slow when manipulating large data sets (strings by far being the worst).
Re-Question: So, does that mean llListInsertList and llDeleteSubList actually make copies, i.e., reallocate, the entire list they're operating on?
Re-Answer: Yup. LSL is a pass-by-value language. Any information passed to a function is copied to that function's stack-frame before the function is run. This means that in practical terms, you need twice as much memory to insert or delete a sublist. (See the notes on the llListInsertList and llDeleteSubList pages to eliminate some confusion about the "manipulation" they do.)
Q: Why are there so many llList2* functions?
A: LSL2 doesn't support run-time typing, meaning you have to actually specify the type of each variable. The Lindens could have implemented a single function, llList2String, then required explicit typecasting, as in (integer)llList2String(foo, 0). However, that isn't as memory- or CPU-efficient as llList2Integer(foo,0) (yes, really) and the amount of work required for the Lindens to implement seperate functions for each type was negligible.
You can still typecast values stored in a list, of course, but it's advised to use the llList2* functions, unless it's a vector or rotation stored as a string, in which case you should cast to a vector or rotation after using llList2String. llList2Vector and llList2Rotation do not cast from strings automatically. See the next question for more.
Q: Have the old problems concerning the odd behavior of llList2Vector and llList2Rot when requesting a TYPE_STRING element from the list been fixed yet?
A: No. If a list element is a string containing text that would otherwise be directly typecast to a vector or rotation, It will not be converted. The resulting vector or rotation will be ZERO_VECTOR or ZERO_ROTATION respectively. This is a bug. To get around it, use llList2String to retrieve elements from your list, then cast them to vectors or rotations as needed: (vector)llList2String(positions,2);
Lists can be conveniently passed as a single string using the
CSV functions. For example, this is useful for sending complex data between objects via
listen or within
linked objects with
llMessageLinked. Or not, if you would be passing data with vectors, rotations, or strings with commas.
llDumpList2String and
llParseString2List are recommended for safe passing of lists. For an example of this method see
ExampleListConversion.
Functions |
Types