User:ANSI Soderstrom/Simple LSL Array (Associative)

From Second Life Wiki
Jump to: navigation, search

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>