Difference between revisions of "Category:LSL List"

From Second Life Wiki
Jump to navigation Jump to search
(→‎Comparing Lists: Complete with != operator and fix example.)
 
(10 intermediate revisions by 6 users not shown)
Line 1: Line 1:
{{LSL Header|ml=*}}{{LSLC|}}{{LSLC|Types}}
{{LSL Header|ml=*}}{{LSLC|}}{{LSLC|Types}}
{{RightToc}}
{{RightToc}}
A list is a special kind of data type which can contain zero or more elements.
 
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.
Lists are signified by square brackets surrounding their elements; the elements inside are separated by commas.


Examples:
Examples:
<lsl>[0,1,2,3,4]
<source lang="lsl2">[0, 1, 2, 3, 4]


["Yes","No","Perhaps"]</lsl>
["Yes", "No", "Perhaps"]</source>


(Note: to be clear for those who have other programming backgrounds, there are no arrays in LSL: only lists.)
(Note: to be clear for those who have other programming backgrounds, there are no arrays in LSL: only lists.)
Line 15: Line 16:
====Diverse Data Types====
====Diverse Data Types====


Not all elements in a list need to be the same type of element. In the same list, you can store strings, integers, floats, vectors, etc, right side by side.
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.


Example:
Example:
<lsl>//a list with an integer, a float, a string, and a vector.
<source lang="lsl2">//a list with an integer, a float, a string, and a vector.
[1,14.154,"Isn't this fun?",<0,0,0>]</lsl>
[1, 14.154, "Isn't this fun?", <0,0,0>]</source>


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


<lsl>[1, "one", 2, "two"] + [3, "three"] returns [1, "one", 2, "two", 3, "three"]</lsl>
<source lang="lsl2">[1, "one", 2, "two"] + [3, "three"] returns [1, "one", 2, "two", 3, "three"]</source>
not  
not  
<lsl>[1, "one", 2, "two", [3, "three"]]</lsl>
<source lang="lsl2">[1, "one", 2, "two", [3, "three"]]</source>


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


If for some reason, though, you need to test what data type an element is in a list, you can use the [[llGetListEntryType]] function.
If for some reason, though, you need to test what data type an element is in a list, you can use the [[llGetListEntryType]] function.
Tip! When adding a [[float]] to a list, always add it with a decimal point (e.g 1.0 as opposed to 1) to ensure that it is preserved as a float.


List can be directly typecast into string
List can be directly typecast into string
<lsl>default
<source lang="lsl2">default
{
{
     touch_start(integer total_number)
     touch_start(integer total_number)
     {   
     {   
         list a = ["abc",1,2,3.14,<0,0,0>];
         list MyList = ["abc", 1, 2, 3.14, <0,0,0>];
         llOwnerSay((string)a); // outcome:  abc123.140000<0.000000, 0.000000, 0.000000>
         llOwnerSay( (string) MyList ); // outcome:  abc123.140000<0.000000, 0.000000, 0.000000>
     }
     }
}</lsl>
}</source>
 
<source lang="lsl2">
    integer min; integer max; integer total;
    llSay(0, (string) ["Minimum: ", min, "  Maximum: ", max, "  Total: ", total] );  // requires 1 explicit cast instead of 3
</source>


or can use a [[do while]] condition to say each list item separately
or can use a [[do while]] condition to say each list item separately
<lsl>default
<source lang="lsl2">default
{
{
     touch_start(integer total_number)
     touch_start(integer total_number)
     {   
     {   
         list a = ["abc","def","ghi","jkl","lmn","opq"];
         list MyList = ["abc", "def", "ghi", "jkl", "lmn", "opq"];
         integer i;
         integer i;
         integer s = llGetListLength(a);
         integer length = llGetListLength(MyList);
         do
         do
        llOwnerSay(llList2String(a,i));
            llOwnerSay(llList2String(MyList, i) );
         while(s>++i);
         while(++i < length);
     }
     }
}</lsl>
}</source>


=== Common List Operations ===
=== Common List Operations ===
====Counting place in a list vs list length====
====Counting place in a list vs list length====


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


<lsl>["Yes","No","Perhaps"]</lsl>
<source lang="lsl2">["Yes", "No", "Perhaps"]</source>


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:
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:


<lsl>integer length = llGetListLength(mylist);</lsl>
<source lang="lsl2">integer length = llGetListLength(mylist);</source>


BUT, counting to determine an element's place in its list (aka "indexing") starts at 0 -- NOT 1.
BUT, counting to determine an element's place in its list (aka "indexing") starts at 0 -- NOT 1.
Line 76: Line 80:
Consequently, if you have 7 elements in a list, the last item in the list will be at position 6.
Consequently, if you have 7 elements in a list, the last item in the list will be at position 6.


Thus to retrieve the last element in a list, without having to know in advance what position it is at, you can just go:
Positions in a list can also be counted from the right-hand end progressing to the left by using negative indexes.


<lsl>integer length = llGetListLength(mylist);
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.
string item = llList2String(myList,length - 1);</lsl>


====List Limits====
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:


''(As of 2/20/11 these limits do not appear to apply for both LSO and Mono.)''
<source lang="lsl2">
string LastItem  = llList2String(myList, -1);
string LastButOne = llList2String(mylist, -2);  // etc.
</source>


While a script is running, a list can grow dynamically as large as needed, limited only by the amount of memory that is available in the script.
However, at compile (aka save) time, there is a 72 element limit to pre-defined lists hardcoded in the script. Such long, predefined lists are common, for example, when someone is offering the user a plethora of colour choices.
Tip! If you really need 72 or more such choices in a pre-defined list, just make 2 (or more) lists that don't upset the compiler, and join them together in state_entry() or wherever appropriate:
<lsl>biggerlist = biglist01 + biglist02;</lsl>


====Adding an Element to a list====
====Adding an Element to a list====
Line 97: Line 96:
There are several ways used to add an element to an existing list via prepending/appending:
There are several ways used to add an element to an existing list via prepending/appending:


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


=====Notes=====
=====Notes=====
* As of 8/8/2009 Method 1 gives significant savings over any other method used in Mono-LSL.
* 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.
** 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.
** Method 1 will consume more memory than other methods in LSO-LSL.
* As of 8/8/2009 Method 7 returns the best value for savings in LSO-LSL.
* As of 8/8/2009 Method 7 returns the best memory savings in LSO-LSL.
** Method 7 is better than Method 4 due to the fact that Method 7 takes up less script overhead.
** Method 7 test script compiled to have a start memory of 15878, while Method 4 compiled to have a start memory of 15871. As a result Method 7 had more free memory than Method 4 at the end of the test operation.
* Methods 2 & 3 compile to the same thing.
* Methods 2 & 3 compile to the same thing.
* Methods 5 & 6 compile to the same thing.
* Methods 4 & 5 compile to the same thing.
* Methods 5, 6 & 7 have a bytecode savings over methods 2, 3 & 4 respectively, though there is an LSO-LSL VM bug that causes the string & key typecasts to not stick properly: {{Jira|SVC-1710}}.
* 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: {{Jira|SVC-1710}}. (It helps reduce heap fragmentation, which would otherwise result in unusable blocks of heap memory){{Footnote|This method was invented and popularized by {{User|Strife Onizuka}}|This method was invented and popularized by Strife Onizuka}}. In Mono-LSL it provides no significant memory advantage or disadvantage.
* Methods 4 & 7 can result in a considerable memory savings in LSO-LSL over methods 2, 3, 5 & 6 (it helps reduce heap fragmentation, which would otherwise result in unusable blocks of heap memory){{Footnote|This method was invented and popularized by {{User|Strife Onizuka}}|This method was invented and popularized by Strife Onizuka}}. 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.
** Depending upon the situation (in LSO-LSL) this method may not provide any advantage what so ever. If in doubt profile the script with and without using this method.


====Joining Lists (aka Concatenation)====
====Joining Lists (aka Concatenation)====
Line 122: Line 118:
Lists can be joined simply by using the + sign:
Lists can be joined simply by using the + sign:


<lsl>newlist = list01 + list02;
<source lang="lsl2">newlist = list01 + list02;


newlist = list01 + ["red","brown",<0,0,0>];</lsl>
newlist = list01 + ["red","brown",<0,0,0>];</source>


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: 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.


====Clearing a List====
====Clearing a List====


To clear a list, set it equal to two square, empty brackets like this:
To clear a list, set it equal to a null list like this:
 
<lsl>myList = [];</lsl>


<source lang="lsl2">myList = [];</source>


====Passing a List Into a Function====
====Passing a List Into a Function====
Line 140: Line 136:
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:
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:


<lsl>myList = llListReplaceList(myList, ["myString"], 2, 2);</lsl>
<source lang="lsl2">myList = llListReplaceList(myList, ["myString"], 2, 2);</source>


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 [[llListSortList]]() (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:
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:


<lsl>myList = llListReplaceList((myList = []) + myList, ["myString"], 2, 2);</lsl>
<source lang="lsl2">myList = llListReplaceList((myList = []) + myList, ["myString"], 2, 2);</source>


The effect of this is to greatly reduce the memory usage, in both LSO-LSL and Mono VMs, and also reduce the fragmentation of memory. 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:
The effect of this is to greatly reduce the memory usage and [[LSO Memory Layout|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:


<lsl>list list1 = ["a", "b", "c"];
<source lang="lsl2">list list1 = ["a", "b", "c"];
list2 = ["d", "e", "f"];
list2 = ["d", "e", "f"];
list3 = (list1 = list2 = []) + list1 + list2;</lsl>
list3 = (list1 = list2 = []) + list1 + list2;</source>


====Processing a List Into Another List====
====Processing a List Into Another List====
Line 156: Line 152:
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:
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:


<lsl>list myOutput = [];
<source lang="lsl2">list myOutput = [];


integer i = 0; integer x = myList != [];
integer i = 0; integer x = myList != [];
Line 168: Line 164:
   // Do some work here:
   // Do some work here:
   myOutput += llList2List(myList, i, i); // A silly bit of example work
   myOutput += llList2List(myList, i, i); // A silly bit of example work
}</lsl>
}</source>


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.
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:
<source lang="lsl2">
    if ( [1,2,3,4] == [0,0,0,0] )
    {
        // TRUE path
    }
    else
    {
        // FALSE path
    }
</source>
will take the TRUE path.
The <code>!=</code> operator, on the other hand, breaks the LSL rule that comparisons only return <code>TRUE</code> or <code>FALSE</code>, and instead returns the difference of the lengths of both lists. Consequently, both statements below are equivalent, and both <code>a</code> and <code>b</code> will be equal to <code>-2</code> after executing this:
<source lang="lsl2">
    integer a = [1,2] != [3,4,5,6];
    integer b = llGetListLength([1,2]) - llGetListLength([3,4,5,6]);
</source>
See also '[[ListCompare]]' for comparing if two lists are really equal including the contents.


== Strided lists ==
== Strided lists ==


One common use of lists is to duplicate the functionality of structured collections of data (aka <i>structs</i>). Such collections, available in many programming languages, are absent from LSL.
One common use of lists is to duplicate the functionality of structured collections of data (aka <i>structs</i>). Such collections, available in many programming languages, are absent from LSL.
Line 183: Line 204:
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:
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:


<lsl>list demographics = ["John Adams", "male", "2007-06-22", "Shirley Bassey", "female", "2005-11-02", "Matt Damon", "male", "2008-05-19"];</lsl>
<source lang="lsl2">list demographics = ["John Adams", "male", "2007-06-22", "Shirley Bassey", "female", "2005-11-02", "Matt Damon", "male", "2008-05-19"];</source>


This example has a <i>stride</i> of three, because each grouping (or stride) has three data elements. Index 0 ("John Adams") is the start of the first instance (because list counting starts a 0), index 3 ("Shirley Bassey") is the start of the second instance, and so on.
This example has a <i>stride</i> of three, because each grouping (or stride) has three data elements. Index 0 ("John Adams") is the start of the first instance (because list counting starts a 0), index 3 ("Shirley Bassey") is the start of the second instance, and so on.
Line 191: Line 212:
To add another person to the above list, you would do this:
To add another person to the above list, you would do this:


<lsl>demographics += ["Dorthy Lamour", "female", "2010-01-22"];</lsl>
<source lang="lsl2">demographics += ["Dorthy Lamour", "female", "2010-01-22"];</source>
 


You cannot do any kind of fancy data analysis or manipulation with strided lists, as you can in off-world databases or spreadsheets, but they can meet some limited, in-world needs, if you don't have the resources to tie-in off-world tools. It should be noted that when manipulating extremely large strided lists, that if you expect to be editing the lists that you may wish to use one list for each "column", this may be more complex but significantly reduces the amount of memory required when manipulating the lists, though it will be a lot more difficult to sort.
It should be noted that when manipulating extremely large strided lists, that if you expect to be editing the lists that you may wish to use one list for each "column", this may be more complex but significantly reduces the amount of memory required when manipulating the lists, though it will be a lot more difficult to sort.


Here are the tools we do have for strided lists:
Here are the tools we do have for strided lists:
Line 204: Line 224:
*[[llListRandomize]]
*[[llListRandomize]]
*[[llListSort]]
*[[llListSort]]
The function [[llListStatistics]] can, with care, be used for strided lists as it will silently ignore non integer and non float items.





Latest revision as of 05:25, 1 May 2017

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.

Examples:

[0, 1, 2, 3, 4]

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

(Note: to be clear for those who have other programming backgrounds, there are no arrays in LSL: only lists.)


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.

Example:

//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"]

not

[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

default
{
     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

default
{
     touch_start(integer total_number)
    {   
        list MyList = ["abc", "def", "ghi", "jkl", "lmn", "opq"];
        integer i;
        integer length = llGetListLength(MyList);
        do
            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:

  1. myList = [new_item] + myList;   // Best method for pre-pending in Mono-LSL. Note: a single new item is presented as a list
    
  2. myList = myList + new_item;     // Best method for appending a single new entry in Mono. Note the new item is NOT presented as a list
    
  3. myList += new_item;             // appended item with simplified syntax
    
  4. myList = myList + [new1, new2]; // appended list concatenation (less efficient in Mono for a single new item)
    
  5. myList += [new1, new2];         // appended list concatenation with simplified syntax
    
  6. myList = (myList=[]) + myList + [new_item]; // Recommended for LSO. Appended list concatenation with memory fragmentation optimization
    
  7. myList = (myList=[]) + myList + new_item;   // Recommended for LSO-LSL: appended item with memory fragmentation optimization
    
Notes
  • 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.

Clearing a List

To clear a list, set it equal to a null list like this:

myList = [];

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
    }
    else
    {
        // 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:

list demographics = ["John Adams", "male", "2007-06-22", "Shirley Bassey", "female", "2005-11-02", "Matt Damon", "male", "2008-05-19"];

This example has a stride of three, because each grouping (or stride) has three data elements. Index 0 ("John Adams") is the start of the first instance (because list counting starts a 0), index 3 ("Shirley Bassey") is the start of the second instance, and so on.

It is important that the pieces of information in each grouping are always entered in the same sequence for every instance of the grouping in the list! In the example above, this means that the name needs to be always the first of the three related elements. You should consider carefully the order in which you record information because the function to sort a list, llListSort, will only sort on the first element of the instances. In other words, if the avatar's rez date were the most important attribute for your script, then you would need to record it first, and the name second. If you wish to be able to sort by avatar last name rather than first name, the name should be added to the list in Lastname FirstName format (avoiding a comma, though, of course, unless you wanted LastName and FirstName treated as separate elements in the list.)

To add another person to the above list, you would do this:

demographics += ["Dorthy Lamour", "female", "2010-01-22"];

It should be noted that when manipulating extremely large strided lists, that if you expect to be editing the lists that you may wish to use one list for each "column", this may be more complex but significantly reduces the amount of memory required when manipulating the lists, though it will be a lot more difficult to sort.

Here are the tools we do have for strided lists:


The following three (as of July 2008) native LSL functions can be used with strided lists:

The function llListStatistics can, with care, be used for strided lists as it will silently ignore non integer and non float items.


Here are some additional, user-created functions for working with strided lists:

function purpose
ListStridedMove Moves something in a strided list to another place in the strided list.
ListStridedRemove Removes part of a strided list.
ListStridedUpdate Updates part of a strided list.
ListStridedReorder Reorder the contents of every stride or reorder entire strides.

Extended List Operations

These functions have been created and contributed by LSL users to perform operations not covered by built-in LSL functions.


function purpose
ListCast Processes a list so that its contents are of a single-type.
List_cast Processes a list so that its contents are converted from strings to their respective types.
ListCompare Compares two lists for equality
ListItemDelete Removes one element from a list.
ListKeyCase Changes the values of the whole list into uppercase or lowercase based on input
ListToWholeNumbers Given a list of floats, converts them all to whole numbers (aka integers.)
ListXorY Join two lists to make one new combined list, while also eliminating any resulting duplicates in the new list.
ListXandY This function examines two lists, and returns a new list composed of the elements that both lists have in common.
ListXnotY Show what x list has that y list is missing.
ListXxorY Returns a new list, composed of elements that were in either original script, but not both. Note: This is not the same as getting rid duplicates by preserving just one of each duplicated item. It goes further, and removes both items.
ListXequY Answers the question: is list X identical to list Y?
ListXneqY Answers the question: is list X different from list Y?
Replace Replaces a single occurrence of something in a list with something else that you specify.
Replace All Replaces all occurrences of 'from list' with those in 'to list' in 'src list'. Not as concise as the replace function above, but will handle multiple items at the same time.
ListUnique Given a list of elements, returns a list of only the unique individual elements in that list.
ccFixListDatatypes Walks a list, casts the elements to the appropriate types, and returns a fixed list. Useful for things like llSetPrimitiveParams when you've parsed your data out of a string.
2D Pseudo-Array A way to emulate the behavior of a 2 dimensional array.