Jump to content

LSL Associative Array


You are about to reply to a thread that has been inactive for 67 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hello-

I am an experienced programmer in PHP. I've enjoyed using LSL so far, but one thing that I have relied upon in other languages still seems to escape me in LSL. What about associative arrays? For example, in PHP I might do the following:

<?php
$avatarName = "Toph Bailey"; // string avatarName = "Toph Bailey";
$c = array($avatarName=>1); // list c = [avatarName, 1]; ????
echo $c[$avatarName]; // llSay(0, llList2String(avatarName, avatarName)); ????
?>

In other words, rather than letting index be limited to an integer range from 0 to (mag-1) of a list, could the index instead be a string (label)? This would have enormous benefit for a lot of short-term data storage, such as recent visitors, or scoreboards (until script was reset).

To be forthright, I am trying to write a scorecard that tracks simple clicks from local objects and associates a counter with each avatar's name in an associative list. So far this data type's one-dimensional nature has evaded my comprehension. Am I approaching this from the right angle?

Thank you for any insight!

Edited by Toph Bailey
Link to post
Share on other sites

LSL is a bit awkward, but you can either use a strided list or pair of lists in which names and scores are stored in the same order.  If you use paired lists, for example, you identify the position of an av in one list with 

integer idx = llListFindList(lAvList, llDetectedName(i));

and then use idx to find the score in the same position in your other list:

integer score = llList2Integer(lScores, idx);

If you update one list, you just have to be sure that you keep the other one in sync, so that the values in both lists are always associated.  In many ways, a singlle strided list is even easier because pairs of values in the list are always associated with the same pairs of variables.

  • Like 1
Link to post
Share on other sites

If you're going to do any sorting a strided list is needed: [score, avatar, score, avatar, ...]. If you're keeping track of avatars you should perhaps consider using avatar keys, which are immutable, rather than names which can change, and which can be spoofed.

Link to post
Share on other sites

A word on strided lists, I'm not sure they are beneficial in any way compared to just using two lists.

since lists used as arguments are copied around, it seem that two lists would move around less memory than a strided list?

Link to post
Share on other sites

As @KT Kingsley pointed out, a strided list is required for llListSort() - but otherwise, yeah, the small extra overhead of storing two separate lists might soon be outweighed by not needing to pass-by-value a twice-as-big list.

I'd just add, apropos a-list storage in LSL, that's kinda how Experience Key-Value Pair persistent store works. Retrieval isn't a simple function call but rather an async dataserver event, but the available storage is much greater than a script memory list.

Link to post
Share on other sites

@Toph Bailey

Here is a JSON snippet for SL, in case you want to test a bit, just drop it in a box,  click the box,

then type.. /99 test ... in local chat . :)

it shows a key with multiple values etc...

addReminder( string name , string dateTime, string text )
{
     if (llJsonGetValue ( Reminders, [name] ) == JSON_INVALID)  // if there is not a JSON key-value pair in the JSON object, add one
      {   Reminders = llJsonSetValue ( Reminders, [name,  "Date_Time"], dateTime);     
          Reminders = llJsonSetValue ( Reminders, [name,  "Reminder_Text"], text);                
      }
}

string Reminders;
string name;

default
{
    state_entry()
    {  Reminders = llList2Json( JSON_OBJECT, [] ); 
       llListen(99,"","","");     
    }
    touch_start(integer total_number)
    {   llOwnerSay("Populating...");
      
        name            =  llDetectedName(0);
        string dateTime =  "2020-08-13 16:33 pm";
        string text     =  "Shopping Event";  
         
        addReminder( name , dateTime,  text );
    }
    listen( integer vIntChn, string vStrNom, key vKeySpk, string vStrMsg )
    {
        if( vIntChn == 99)
        {    string info1 = llJsonGetValue ( Reminders, [name, "Date_Time"]) ;
             string info2 = llJsonGetValue ( Reminders, [name, "Reminder_Text"]) ;
             string info3 = llJsonGetValue ( Reminders, [name]) ;
             string info4 = llJsonGetValue ( Reminders, [] ) ;
             llOwnerSay( "Data:\n \nTime: "  + info1  +
                          "\nEvent: "     + info2  +
                          "\n" + name     + " info:. " + info3 +
                          "\nEntire DB: " + info4);             
        }
    }
}

 

Edited by Xiija
Link to post
Share on other sites

I had to do much LSL list updating in my NPCs. I found that up to 128 integers, updating a list, which is actually a recopy, is roughly constant time. Beyond that length, it gets much slower as list length increases. If you're doing a lot of list updating, benchmark. It's not obvious how fast list updates go.

Link to post
Share on other sites

Here's an example of how you could get something close to an associative array in LSL. It uses a strided list for quick iteration of keys, but uses json to store the value to allow more complicated data structure:-

list people;

// Add a person to people
// name: The person's name
// details: JSON Encoded Object containing age, fav_food, shirt_color, description
add_person(string name, string details) {
    people += [name, details];
}

string get_person(string name) {
    integer i;
    integer num_people = llGetListLength(people);
    while (i < num_people) 
    {
        if (name == llList2String(people, i)) 
        {
            return llList2String(people, i + 1);
        }
        i += 2;
    }
    return "";

}

default
{
    state_entry()
    {
        // Adding people to our list of people
        string janet = llList2Json(JSON_OBJECT, [
            "age", 20,
            "fav_food", "pizza",
            "shirt_color", <1,0,0>,
            "description", "Wears a red shirt"
            ]);
        string jack = llList2Json(JSON_OBJECT, [
            "age", 35,
            "fav_food", "yakisoba",
            "shirt_color", <0,1,0>,
            "description", "Wears a green shirt"
            ]);
        add_person("Janet", janet);
        add_person("Jack", jack);
        
        // Retrieving people
        list people_to_retrieve = ["Janet", "Paul", "Jack", "Steve"];
        
        integer i;
        integer num_people_to_retrieve = llGetListLength(people_to_retrieve);
        
        while (i < num_people_to_retrieve) 
        {

            string name = llList2String(people_to_retrieve, i);
            string json = get_person(name);
            if (json != "") 
            {
                integer age         = (integer)llJsonGetValue(json, ["age"]);
                string fav_food        = llJsonGetValue(json, ["fav_food"]);
                vector shirt_color  = (vector)llJsonGetValue(json, ["shirt_color"]);
                string description    = llJsonGetValue(json, ["description"]);

                llSetColor(shirt_color, ALL_SIDES);
                llSay(0, name + " is " + (string)age + " years old. " + description);
                llSay(0, "Favourite food: " + fav_food);

            } else {
                llSetColor(<0,0,0>, ALL_SIDES);
                llSay(0, "I don't know a " + name + "!");
            }
            ++i;
            llSleep(3.0);
        }
    }
}

 

  • Like 2
Link to post
Share on other sites

 

1 hour ago, Extrude Ragu said:

Here's an example of how you could get something close to an associative array in LSL. It uses a strided list for quick iteration of keys, but uses json to store the value to allow more complicated data structure:-

 

a good thing about the method you show is that JSON makes it a whole lot simpler, particularly also when [details] can have different data structures for each [name]

a little thing. We can make the lookup a little bit more efficient. Example:

 

string get_person(string name)
{
   integer i = llListFindList(people, [name]);
   if (i % 2 == 0)  // check that name is a key and not a value in key/value pair [name, details]
   {
      return(llList2String(people, i + 1); // return details
   }  // else not found
   return "";
}
  • Like 1
Link to post
Share on other sites
You are about to reply to a thread that has been inactive for 67 days.

Please take a moment to consider if this thread is worth bumping.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...