User:ANSI Soderstrom/Simple LSL Array (Associative)

From Second Life Wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Leave a comment

Simple LSL Array (Associative)

<lsl> // Simple LSL Array (associative) for your Scripts (useful and very fast) // (C) 02/2010 ANSI Soderstrom

list SOMELIST;

string GET(list ARRAY,list KEY) {

   if(!llGetListLength(KEY)>1) {
      // dont allow lists in lists (yet)
      return "-1";
   }
   integer position;
   do {
       // Have a look to the nearest next possible match (can be a KEY or VALUE)
       position = llListFindList(ARRAY, KEY);
       // position%2 = we point ever to a KEY, not to a VALUE
       // ~position  = only process the condition if the list contains a KEY with the right given spelling (and Type)
       // position   = position should be not zero, we dont want to delete the right KEY, we will return him
       if(position%2 && ~position && position) {
           // no match in this case, delete this pair and process the next pair
           ARRAY = llDeleteSubList(ARRAY,0,position);
       } 
   // loop if
   // ~position  = a further possible match for a KEY or VALUE
   // position%2 = the nearest next possible match is a VALUE. Back to work
   } while (~position && position%2);
   if(~position) {
       // we have a HIT !!! (hurray) return the VALUE
       return llList2String(ARRAY,position+1);
   } else {
       // we are in fact at the end of the list and have no matches
       return "0";
   } 

}

list PUT(list ARRAY,list KEY, list VALUE) {

   if(llGetListLength(KEY)>1 || llGetListLength(VALUE)>1) {
       // dont allow lists in lists (yet)
       // Maybe its smarter at this point to return the whole untouched Array because the script is not broken 
       // if we call this function dynamically
       // return ARRAY;
       return [-1];
   }  
   // just curious and impatient at this point... (i never have enough time and need quick solutions because life is too short)
   // (this means : i hate to execute double-code and we can find the same line some lines below)
   integer position = llListFindList(ARRAY, KEY);
   // maybe we need a helplist. here is a good place to create this list.
   list helparray = [];
   do {
       // !~position = We have in the whole remaining list no KEY with this type, so we add simply the KEY and VALUE and go out.
       if(!~position) { 
           ARRAY += KEY;
           ARRAY += VALUE;
           return helparray + ARRAY;
       }      
       // position%2 = we point ever to a KEY, not to a VALUE
       // ~position  = only process the condition if the list contains KEYs with the right given spelling (and Type)
       // position   = position should be not zero (Oh, its a VALUE), we dont want to delete the right KEY, we will overwrite him  
       if(position%2 && ~position && position) {
           // save the previous list in a second list, so we can work (delete) on parts in the original list without data-loss
           helparray += llList2List(ARRAY,0,position);
           // delete the unwanted stuff
           ARRAY = llDeleteSubList(ARRAY,0,position);
           // search the next match in the (shorter) original list
           position = llListFindList(ARRAY, KEY);     
       } 
   // the next possible match is in fact a VALUE if position%2 != 0. So back to work 
   } while (position%2);
   // We know that the list have definitely the KEY we searching for (because '!~position' is not triggered yet)
   // seems that we have a match (because position==0). We can overwrite the VALUE for the given KEY at this point
   ARRAY = llListReplaceList(ARRAY, VALUE, position + 1, position + 1);
   // re-build the list and back to normal operations
   return helparray + ARRAY;   

}

list ERASE(list ARRAY,list KEY) {

   if(!llGetListLength(KEY)>1) {
       // dont allow lists in lists (yet)
       // Maybe its smarter at this point to return the whole untouched Array because the script is not broken 
       // if we call this function dynamically
       // return ARRAY;
       return [-1];
   }
   // just curious and impatient at this point... (i never have enough time and need quick solutions because life is too short)
   // (this means : i hate to execute double-code and we can find the same line some lines below)
   integer position = llListFindList(ARRAY, KEY);
   // maybe we need a helplist. here is a good place to create this list.
   list helparray = [];
   do {
       // !~position = no match in the whole remaining list. Erase nothing and go out
       if(!~position) { 
           return helparray + ARRAY;
       }    
       // position%2 = we point ever to a KEY, not to a VALUE
       // ~position  = only process the condition if the list contains KEYs with the right given spelling (and Type)
       // position   = Oh, its a VALUE. 
       if(position%2 && ~position && position) {
           // save the previous list in a second list, so we can work (delete) on parts in the original list without data-loss
           helparray += llList2List(ARRAY,0,position);
           // delete the unwanted stuff
           ARRAY = llDeleteSubList(ARRAY,0,position);
           // search the next match in the (shorter) original list
           position = llListFindList(ARRAY, KEY);     
       } 
   // the next possible match is in fact a VALUE if position%2 != 0. Back to work
   } while (position%2);
   // seems that we have a match. We can delete this KEY/VALUE pair
   ARRAY = llDeleteSubList(ARRAY,position, position + 1);
   // re-build the list and back to normal operations    
   return helparray + ARRAY;   

} </lsl>

What do those lines do?

<lsl> default {

   state_entry() {        

       // --------------------------------------------------------------------------------

       // Add new KEY/VALUE to the "Array" while the KEY is non existent
       SOMELIST = PUT(SOMELIST,["KEY"],["VALUE"]);
       SOMELIST = PUT(SOMELIST,[AGENT],[<1,1,1>]);
       SOMELIST = PUT(SOMELIST,["TEST"],["VALUE"]);
       SOMELIST = PUT(SOMELIST,["VALUE"],["TEST"]);

       llSay(0,GET(SOMELIST,["KEY"]));     // Output : VALUE
       llSay(0,GET(SOMELIST,[AGENT]));     // Output : <1.000000, 1.000000, 1.000000>
       llSay(0,GET(SOMELIST,["TEST"]));    // Output : VALUE
       llSay(0,GET(SOMELIST,["VALUE"]));   // Output : TEST

       // --------------------------------------------------------------------------------

       // Overwrite the VALUE from the given KEY if KEY is existent
       SOMELIST = PUT(SOMELIST,["KEY"],["9adba1b4-a733-4a44-8275-f4a666784d8c"]);
       SOMELIST = PUT(SOMELIST,[AGENT],["unknown"]);
       SOMELIST = PUT(SOMELIST,["TEST"],["TEST"]);
       SOMELIST = PUT(SOMELIST,["VALUE"],["VALUE"]);

       llSay(0,GET(SOMELIST,["KEY"]));     // Output : 9adba1b4-a733-4a44-8275-f4a666784d8c
       llSay(0,GET(SOMELIST,[AGENT]));     // Output : unknown
       llSay(0,GET(SOMELIST,["TEST"]));    // Output : TEST
       llSay(0,GET(SOMELIST,["VALUE"]));   // Output : VALUE      

       // --------------------------------------------------------------------------------

       // case sensitive KEY´s
       SOMELIST = PUT(SOMELIST,["AGENT"],[NULL_KEY]);
       SOMELIST = PUT(SOMELIST,[AGENT],[ZERO_ROTATION]);

       llSay(0,GET(SOMELIST,["agent"]));   // Output : 0
       llSay(0,GET(SOMELIST,["AGENT"]));   // Output : 00000000-0000-0000-0000-000000000000
       llSay(0,GET(SOMELIST,[AGENT]));     // Output : <0.000000, 0.000000, 0.000000, 1.000000>

       // --------------------------------------------------------------------------------        

       // Let us play...
       SOMELIST = PUT(SOMELIST,[AGENT],llGetObjectDetails(GET(SOMELIST,["KEY"]),([OBJECT_NAME])));   

       llSay(0,GET(SOMELIST,["KEY"])); // Output : 9adba1b4-a733-4a44-8275-f4a666784d8c
       llSay(0,GET(SOMELIST,[AGENT])); // Output : ANSI Soderstrom  

       // --------------------------------------------------------------------------------           

       // ANSI Soderstrom is not a KEY, only a VALUE
       if(!(integer)GET(SOMELIST,["ANSI Soderstrom"])) {
           llSay(0,"Not in List");
       } else {
           llSay(0,"Found");
       } 
       // Output : Not in List     

       // -------------------------------------------------------------------------------- 

       llSay(0,llList2CSV(SOMELIST));
       /*
           Output :    KEY, 9adba1b4-a733-4a44-8275-f4a666784d8c, 
                       1, ANSI Soderstrom, 
                       TEST, TEST, 
                       VALUE, VALUE, 
                       AGENT, 00000000-0000-0000-0000-000000000000
       */    

       // -------------------------------------------------------------------------------- 

       // Extended behavior

       list WHITELIST;
       list BLACKLIST;

       WHITELIST = [   "1234","ANSI Soderstrom",
                       "4321","Other Name"
                   ];

       BLACKLIST = [   "9876","Invisible Linden",
                       "6789","Visible Linden"
                   ];

       // Does NOTHING (no Target List)
       PUT(WHITELIST,["1234"],["Any Value"]);             

       // Dont touch the Blacklist...
       // Overwrite Whitelist with Blacklist AND CHANGE the Value of the given Name in the Whitelist
       // (because KEY is in Blacklist)        
       WHITELIST = PUT(BLACKLIST,["9876"],["Changed Name"]); 
       llOwnerSay(llList2CSV(WHITELIST));  // Whitelist : 9876, Changed Name, 6789, Visible Linden

       // Dont touch the Blacklist...
       // Overwrite Whitelist with Blacklist AND ADD the given KEY/VALUE to Whitelist
       // (because KEY is not in Blacklist)              
       WHITELIST = PUT(BLACKLIST,["1234"],["Any Value"]);
       llOwnerSay(llList2CSV(WHITELIST));  // Whitelist : 9876, Invisible Linden, 6789, Visible Linden, 1234, Any Value

       // -------------------------------------------------------------------------------- 

       // Simple eval();

       list EVAL = [   "Key 1","Test 1",
                       "Key 2","Test 2",
                       "Key 3","Test 3"
                   ];

       integer i = llGetListLength(EVAL)/2;
       for(;i;--i) {
           llSay(0,GET(EVAL,["Key " + (string)i]));
       }

       // Output:
       // Test 3
       // Test 2
       // Test 1

       // -------------------------------------------------------------------------------- 

       // more complex... (Beware of Traps...)

       list LIST;  
       list TEST;
       string test;

       LIST = PUT(LIST,["1234"],["First Value"]);  
       LIST = PUT(LIST,[1234],["Second Value"]);     

       test = llList2CSV(LIST);
       llSay(0,test);                  // Output : 1234, First Value, 1234, Second Value

       llSay(0,GET(LIST,["1234"]));    // Output : First Value
       llSay(0,GET(LIST,[1234]));      // Output : Second Value   

       TEST = llCSV2List(test);
       llSay(0,llList2CSV(TEST));      // Output : 1234, First Value, 1234, Second Value

       // ARRAY BROKEN AFTER llList2CSV(); !!!
       llSay(0,GET(TEST,["1234"]));    // Output : First Value
       llSay(0,GET(TEST,[1234]));      // Output : 0   

       // --------------------------------------------------------------------------------

       // AGENT is a static integer with the value 1
       SOMELIST = PUT(SOMELIST,[AGENT],["AGENT"]); 

       llSay(0,GET(SOMELIST,[1]));     // Output : AGENT
       llSay(0,GET(SOMELIST,[AGENT])); // Output : AGENT

       // --------------------------------------------------------------------------------        

       // Remember... "AGENT" and AGENT are different, and "AGENT" is a VALUE, not a KEY !!!
       if(!(integer)GET(SOMELIST,["AGENT"])) {
           llSay(0,"Not in List");
       } else {
           llSay(0,"Found");
       }
       // Output : Not in List

       // -------------------------------------------------------------------------------- 
       
       llSay(0,llList2CSV(SOMELIST));
       // Output : KEY, 9adba1b4-a733-4a44-8275-f4a666784d8c, 
       //          1, AGENT, 
       //          TEST, TEST, 
       //          VALUE, VALUE, 
       //          AGENT, 00000000-0000-0000-0000-000000000000
       
       SOMELIST = ERASE(SOMELIST,["KEY"]);
       
       llSay(0,llList2CSV(SOMELIST));
       // Output : 1, AGENT, 
       //          TEST, TEST, 
       //          VALUE, VALUE, 
       //          AGENT, 00000000-0000-0000-0000-000000000000
               
       SOMELIST = ERASE(SOMELIST,[AGENT]);

       llSay(0,llList2CSV(SOMELIST));
       // Output : TEST, TEST, 
       //          VALUE, VALUE, 
       //          AGENT, 00000000-0000-0000-0000-000000000000
               
       SOMELIST = ERASE(SOMELIST,["AGENT"]);
       
       llSay(0,llList2CSV(SOMELIST));
       // Output : TEST, TEST, 
       //          VALUE, VALUE, 
               
       SOMELIST = ERASE(SOMELIST,["VALUE"]);
       
       llSay(0,llList2CSV(SOMELIST));
       // Output : TEST, TEST,      
       
       SOMELIST = ERASE(SOMELIST,["TEST"]);
       llSay(0,llList2CSV(SOMELIST));
       // Output : 
               
       // -------------------------------------------------------------------------------- 

       /* 

       Now you can manage your Settings simple...

       list SETTINGS;

       SETTINGS = PUT(SETTINGS,["owner"],[llGetOwner()]);
       SETTINGS = PUT(SETTINGS,["POS"],[llGetPos()]);

       list API;

       API = PUT(API,["I_HAVE_THE_SETTINGS"],[-34234242]);

       llMessageLinked(LINK_SET,(integer)GET(API,["I_HAVE_THE_SETTINGS"]),llList2CSV(SETTINGS),llGetOwner());

       // -------------------------------------------------------------------------------- 

       list SETTINGS;
       list API;

       API = PUT(API,["I_HAVE_THE_SETTINGS"],[-34234242]);

       link_message(integer sender_num, integer num, string str, key id) {
           // receive a valid message for this state AND try a further Copy Protection
           if(id==llGetCreator() && num==(integer)GET(API,["I_HAVE_THE_SETTINGS"]) {
               SETTINGS = llCSV2List(str);
           } // if     
       } // link_message  

       */
   } 

}

</lsl>