LSL List


A list is a special kind of data type which can contain zero or more elements of any of the other data types recognised in LSL.

Lists are signified by square brackets surrounding their elements; the elements inside are separated by commas.


[0, 1, 2, 3, 4]
["Yes", "No", "Perhaps"]

Diverse Data Types

Elements in a list do not need to be all of the same type. In the same list, you can store strings, integers, floats, vectors, and rotations, right side by side.


//a list with an integer, a float, a string, and a vector.
[1, 14.154, "Isn't this fun?", <0,0,0>]

However, a list may not contain another list (i.e. you can't nest them.)

[1, "one", 2, "two"] + [3, "three"] returns [1, "one", 2, "two", 3, "three"]


[1, "one", 2, "two", [3, "three"]]

When you add an element to a list, the list remembers automatically what data type the value was.

Generally, because you're the one adding something to a list, you know what datatype is in what place in the list, and you retrieve it out of the list with the appropriate llList2<type> function such as: llList2String, llList2Vector, etc. (more on this later.)

If for some reason, though, you need to test what data type an element is in a list, you can use the llGetListEntryType function.

List can be directly typecast into string.

     touch_start(integer total_number)
        list MyList = ["abc", 1, 2, 3.14, <0,0,0>];
        llOwnerSay( (string) MyList ); // outcome:  abc123.140000<0.000000, 0.000000, 0.000000>
     integer min; integer max; integer total;
     llSay(0, (string) ["Minimum: ", min, "  Maximum: ", max, "  Total: ", total] );  // requires 1 explicit cast instead of 3

or can use a do while condition to say each list item separately

     touch_start(integer total_number)
        list MyList = ["abc", "def", "ghi", "jkl", "lmn", "opq"];
        integer i;
        integer length = llGetListLength(MyList);
            llOwnerSay(llList2String(MyList, i) );
        while(++i < length);

Common List Operations

Counting place in a list vs list length

It is important at the outset to note the following (which can trip up even experienced minds when they are battle-weary):

["Yes", "No", "Perhaps"]

The length of this list is 3, because it has 3 elements in it. The length of a list is returned by the llGetListLength() function:

integer length = llGetListLength(mylist);

BUT, counting to determine an element's place in its list (aka “indexing”) starts at 0 – NOT 1.

The position of “Yes” in the above list is 0, “No” is at position 1, and “Perhaps” is at position 2.

Consequently, if you have 7 elements in a list, the last item in the list will be at position 6.

Positions in a list can also be counted from the right-hand end progressing to the left by using negative indexes.

Then the position of the right-most entry is -1, and the position of the left-most entry is the negative of the list length.

Thus to retrieve elements near to the end of a list, without having to know in advance its forward position, or the list length, you can just say:

string LastItem   = llList2String(myList, -1);
string LastButOne = llList2String(mylist, -2);   // etc.

Adding an Element to a list

There are several ways used to add an element to an existing list via prepending/appending:

    myList = [new_item] + myList;   // Best method for pre-pending in Mono-LSL. Note: a single new item is presented as a list
    myList = myList + new_item;     // Best method for appending a single new entry in Mono. Note the new item is NOT presented as a list
    myList += new_item;             // appended item with simplified syntax
    myList = myList + [new1, new2]; // appended list concatenation (less efficient in Mono for a single new item)
    myList += [new1, new2];         // appended list concatenation with simplified syntax
    myList = (myList=[]) + myList + [new_item]; // Recommended for LSO. Appended list concatenation with memory fragmentation optimization
    myList = (myList=[]) + myList + new_item;   // Recommended for LSO-LSL: appended item with memory fragmentation optimization


  • Method 1 is the most memory efficient under Mono-LSL. But not under LSO.
    • Note that prepending the new_item without brackets negates any memory savings in Mono-LSL.
    • Method 1 will consume more memory than other methods in LSO-LSL.
  • As of 8/8/2009 Method 7 returns the best memory savings in LSO-LSL.
  • Methods 2 & 3 compile to the same thing.
  • Methods 4 & 5 compile to the same thing.
  • Methods 6 & 7 can result in a considerable memory savings in LSO-LSL over methods though there is an LSO-LSL VM bug that causes the string & key typecasts to not stick properly: SVC-1710. (It helps reduce heap fragmentation, which would otherwise result in unusable blocks of heap memory)[1]. In Mono-LSL it provides no significant memory advantage or disadvantage.
    • Depending upon the situation (in LSO-LSL) this method may not provide any advantage whatsoever. If in doubt profile the script with and without using this method.

Joining Lists (aka Concatenation)

Lists can be joined simply by using the + sign:

newlist = list01 + list02;
newlist = list01 + ["red","brown",<0,0,0>];

Note: The above example actually creates 3 lists in memory while the command runs, even though just one is returned. This can affect memory usage.

Note: Concatenation can ONLY be done by executable code in LSL, you cannot use + while declaring a global list.

Passing a List Into a Function

Passing a list into a function is little different than passing any other data type, however, there are some useful cases to be aware of:

myList = llListReplaceList(myList, ["myString"], 2, 2);

In the above code, we call llListReplaceList(), an innocent enough operation, however, due to the way passing of lists, and functions such as llListReplaceList(), llDeleteSubList(), llList2List() and llListSort() (and others), work, you can end up using two, three, or even four times the amount of memory required to store your list, just by calling that function! To avoid this problem, we can use a small piece of optimisation; if you know that the list you're passing into such a function will never be read again (for example if the result of the function will overwrite the list) then we can do this:

myList = llListReplaceList((myList = []) + myList, ["myString"], 2, 2);

The effect of this is to greatly reduce the memory usage and fragmentation in LSO-LSL but has no effect in Mono-LSL (fragmentation does not impact scripts in Mono). This technique is sometimes referred to as “Voodoo magic”. This can also work for other cases other than function-calls, for example when concatenating lists (above), you may find that this nearly eliminates any memory problem:

list list1 = ["a", "b", "c"];
list2 = ["d", "e", "f"];
list3 = (list1 = list2 = []) + list1 + list2;

Processing a List Into Another List

A more complex case, but sometimes when processing a large list you may find that you are producing a similarly large list as a result. In such cases there is a very large risk of running out of memory. As a result, in any case where you know you will, or might, be working on a particularly large list, it will often be worth manipulating them similarly to:

list myOutput = [];
integer i = 0; integer x = myList != [];
for (; i < x; ++i) {
    if (i > 10) { // Prune list every 10 elements
        myList = llDeleteSubList((myList = []) + myList, 0, i - 1);
        x -= i;
        i = 0;
   // Do some work here:
   myOutput += llList2List(myList, i, i); // A silly bit of example work

This method (deleting every few list entries or strides) is preferable to deleting an entry every loop, as the cost of calling llDeleteSubList() is very high. It is up to the scripter to decide what their optimal chunk-size is for pruning an input list, as you will need to balance memory use with delete cost.

Comparing Lists

Equality test on lists does not compare contents, only the length. Hence:

    if ( [1,2,3,4] == [0,0,0,0] )
        // TRUE path
        // FALSE path

will take the TRUE path.

The != operator, on the other hand, breaks the LSL rule that comparisons only return TRUE or FALSE, and instead returns the difference of the lengths of both lists. Consequently, both statements below are equivalent, and both a and b will be equal to -2 after executing this:

    integer a = [1,2] != [3,4,5,6];
    integer b = llGetListLength([1,2]) - llGetListLength([3,4,5,6]);

See also 'ListCompare' for comparing if two lists are really equal including the contents.

Strided lists

One common use of lists is to duplicate the functionality of structured collections of data (aka structs). Such collections, available in many programming languages, are absent from LSL.

In-world in SL, (still as of July 2008), a strided list is the closest you can get to storing limited amounts of data in some kind of structure that you can access and manipulate in a few, limited ways.

Strided lists allow you to store related data pieces grouped (aka “strided”) in sets. You can determine how many pieces of data in each “grouping.”

An example is best at this point. You might use a strided list to track the names, gender and rez dates of a group of avatars:

QR Code
QR Code wiki:scripting_portal:lsl_types:list (generated for current page)