Associative Array Emulator
This is a library to emulate associative arrays using lists. I've been using this code in more than a few projects and decided to release it here. From here on out I will call them 'dictionaries' or 'dicts' because I come from a FORTH background ^o.o^
Using this library is relatively simple. To create a dictionary, declare it using:
list dict=dictNew(<elements>);
This initializes the list to be usable as a dictionary.
To set an element:
dict = dictSetItem(dict,"<key>",[list of elements]);
The list of elements should equal the same number of items as you declared in dictNew(). If it does not, the list will be chopped or padded with null keys.
<lsl> // Alynna's Dictionary Tools, released GPLv3, anyone can use it. Created by Alynna Vixen. Try // This library emulates dictionaries (associative arrays) using lists.
// Create a new dictionary, which just creates a list initialized with the number of data elements per key. // The initialized dictionary is returned, with no keys. list dictNew(integer elements) {
return [elements];
}
// Delete an item from the dictionary. // If the key is not found or null, the result is an unchanged dictionary, // Else it is the dictionary with the key and its data removed. list dictDelItem(list dict, string dkey) {
if (dkey == "") return dict; dkey = llToLower(dkey); list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); integer loc = llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); if (loc<0) return dict; else return [elements] + llDeleteSubList(tmp,loc*(elements+1),(loc*(elements+1))+elements);
}
// Set an item in the dictionary. // If the key is null, the dictionary is returned unchanged. // If the key is not found, it and the data is appended to the current dictionary, // Else, the data given replaces the data in the given key, the key remains unchanged. // The changed dictionary is returned. list dictSetItem(list dict, string dkey, list data) {
if (dkey == "") return dict; dkey = llToLower(dkey); list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); integer loc = llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); if (loc<0) return dict + [dkey] + llList2List(data+[NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY],0,elements-1); else return [elements] + llListReplaceList(tmp, [dkey] + llList2List(data+[NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY,NULL_KEY],0,elements-1),loc*(elements+1),(loc*(elements+1)+elements));
}
// Get an item from the dictionary. // If the key is not found, or null, the result is an empty list. // If the key is found, the result is the list of values for that key in the dictionary. list dictGetItem(list dict, string dkey) {
if (dkey == "") return []; dkey = llToLower(dkey); list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); integer loc = llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); if (loc<0) return []; else return llList2List(tmp,loc*(elements+1)+1,loc*(elements+1)+elements);
}
// Get a list of elements from the dictionary // If the element is -1, returns a list of all valid keys. // Else a list of the element values for every key is returned. list dictGetElems(list dict, integer elem) {
list tmp = llList2List(dict,elem+2,-1); integer elements = llList2Integer(dict,0); return llList2ListStrided(tmp,0,-1,elements+1);
} // An alias for dictGetElems(<list>, -1) list dictGetKeys(list dict) {
return dictGetElems(dict, -1);
}
// Set an element within an item in the dictionary. // The dictionary is returned unchanged, if the key is not found, the element out of range, or key is null. // Else, the dict is returned with the element changed. list dictSetElement(list dict, string dkey, integer elem, list data) {
if (dkey == "") return dict; dkey = llToLower(dkey); list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); integer loc = llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); if (elem<0 || elem>elements-1) return dict; if (loc<0) return dict; else return [elements] + llListReplaceList(tmp, llList2List(data,0,0),loc*(elements+1)+(elem+1),(loc*(elements+1)+(elem+1)));
}
// Get a list of elements from the dictionary // If the element is -1, returns a list of all valid keys. // Else a list of the element values for every key is returned. list dictGetElement(list dict, string dkey, integer elem) {
if (dkey == "") return []; dkey = llToLower(dkey); list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); integer loc = llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); if (loc>=0) return llList2List(tmp,loc*(elements+1)+(elem+1),loc*(elements+1)+(elem+1)); else return [];
}
// Returns the position in the dictionary of a key. If it is not found, will return -1. // Good for testing for a key's existence. integer dictFindKey(list dict, string dkey) {
if (dkey == "") return -1; else { list tmp = llList2List(dict,1,-1); integer elements = llList2Integer(dict,0); return llListFindList(llList2ListStrided(tmp,0,-1,elements+1),[dkey]); }
}
// Simply returns the number of items in the dictionary. integer dictCount(list dict) {
return (llGetListLength(dict)-1)/(llList2Integer(dict,0)+1);
}
// Delete the stuff below here its just for testing, unless you want to see how everything works. // In that case, drop this entire script into a box, compile it and click the box.
string stackdump(list x) {
return "["+llDumpList2String(x, "] | [")+"]";
} default {
touch_start(integer total_number) { llSay(0,"Begin AlyDictLib: One element tests."); llSay(0,"x = dictNew(1)"); list x = dictNew(1); list y; llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'kitty', ['cute'])"); x = dictSetItem(x, "kitty", ["cute"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'puppy', ['cuter'])"); x = dictSetItem(x, "puppy", ["cuter"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'foxy', ['cutest'])"); x = dictSetItem(x, "foxy", ["cutest"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictDelItem(x, 'kitty')"); x = dictDelItem(x, "kitty"); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'bunny', ['cute'])"); x = dictSetItem(x, "bunny", ["cute"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'foxy', ['supercute'])"); x = dictSetItem(x, "foxy", ["supercute"]); llSay(0,"x: "+stackdump(x));
llSay(0,"y = dictGetItem(x, 'foxy')"); y = dictGetItem(x, "foxy"); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetItem(x, 'bunny')"); y = dictGetItem(x, "bunny"); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetElems(x, 0)"); y = dictGetElems(x, 0); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetKeys(x)"); y = dictGetKeys(x); llSay(0,"y: "+stackdump(y));
llSay(0," ---------- "); llSay(0,"Begin AlyDictLib: Multi element tests."); llSay(0,"x = dictNew(3)"); x = dictNew(3); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'kitty', ['feline', 'cute', 'meow'])"); x = dictSetItem(x, "kitty", ["feline", "cute", "meow"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'puppy', ['canine', 'cuter', 'bark'])"); x = dictSetItem(x, "puppy", ["canine", "cuter", "bark"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'foxy', ['vulpine', 'cutest', 'yip'])"); x = dictSetItem(x, "foxy", ["vulpine", "cutest", "yip"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictDelItem(x, 'kitty')"); x = dictDelItem(x, "kitty"); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'bunny', ['lapine', 'cute', 'churr'])"); x = dictSetItem(x, "bunny", ["lapine", "cute", "churr"]); llSay(0,"x: "+stackdump(x));
llSay(0,"x = dictSetItem(x, 'foxy', ['vulpine', 'supercute', 'yerf'])"); x = dictSetItem(x, "foxy", ["vulpine", "supercute", "yerf"]); llSay(0,"x: "+stackdump(x));
llSay(0,"y = dictGetItem(x, 'foxy')"); y = dictGetItem(x, "foxy"); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetItem(x, 'bunny')"); y = dictGetItem(x, "bunny"); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetElems(x, 0)"); y = dictGetElems(x, 0); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetElems(x, 1)"); y = dictGetElems(x, 1); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetElems(x, 2)"); y = dictGetElems(x, 2); llSay(0,"y: "+stackdump(y));
llSay(0,"y = dictGetKeys(x)"); y = dictGetKeys(x); llSay(0,"y: "+stackdump(y));
llSay(0,"x = dictSetElement(x, 'foxy', 2, ['yip'])"); x = dictSetElement(x, "foxy", 2, ["yip"]); llSay(0,"x: "+stackdump(x));
llSay(0,"y = dictGetElement(x, 'bunny', 1)"); y = dictGetElement(x, "bunny", 1); llSay(0,"y: "+stackdump(y)); llSay(0,"dictFindKey(x, 'foxy'): "+(string)dictFindKey(x,"foxy")); llSay(0,"dictFindKey(x, 'ferret'): "+(string)dictFindKey(x,"ferret")); llSay(0,"dictCount(x): "+(string)dictCount(x));
llSay(0," ---------- "); llSay(0,"Begin AlyDictLib: Error handling tests.");
llSay(0,"x = dictNew(3)"); x = dictNew(3); llSay(0,"x: "+stackdump(x));
llSay(0,"Extra items: x = dictSetItem(x, 'kitty', ['feline', 'cute', 'meow', 'garbage'])"); x = dictSetItem(x, "kitty", ["feline", "cute", "meow", "garbage"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Insufficient items: x = dictSetItem(x, 'puppy', ['canine', 'cuter'])"); x = dictSetItem(x, "puppy", ["canine", "cuter"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Mixed items (technically NOT an error): x = dictSetItem(x, 'foxy', ['vulpine', 9001, 'yip'])"); x = dictSetItem(x, "foxy", ["vulpine", 9001, "yip"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Set of null key: x = dictSetItem(x, , ['vulpine', 9001, 'yip'])"); x = dictSetItem(x, "", ["vulpine", 9001, "yip"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Get of null key: y = dictGetItem(x, )"); y = dictGetItem(x, ""); llSay(0,"y: "+stackdump(y));
llSay(0,"Deletion of non-existent item: x = dictDelItem(x, 'ferret')"); x = dictDelItem(x, "ferret"); llSay(0,"x: "+stackdump(x));
llSay(0,"Addition of item: x = dictSetItem(x, 'bunny', ['lapine', 'cute', 'churr'])"); x = dictSetItem(x, "bunny", ["lapine", "cute", "churr"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Correction of item: x = dictSetElement(x, 'puppy', 2, ['bark'])"); x = dictSetElement(x, "puppy", 2, ["bark"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Get of non-existent item: y = dictGetItem(x, 'ferret')"); y = dictGetItem(x, "ferret"); llSay(0,"y: "+stackdump(y));
llSay(0,"Get of null key: y = dictGetItem(x, )"); y = dictGetItem(x, ""); llSay(0,"y: "+stackdump(y));
llSay(0,"Set of nonexistent element: x = dictSetElement(x, 'foxy', 4, ['yerf'])"); x = dictSetElement(x, "foxy", 4, ["yerf"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Get of nonexistent element: y = dictGetElement(x, 'bunny', 6)"); y = dictGetElement(x, "bunny", 6); llSay(0,"y: "+stackdump(y)); llSay(0,"Set of nonexistent key: x = dictSetElement(x, , 4, ['yerf'])"); x = dictSetElement(x, "", 4, ["yip"]); llSay(0,"x: "+stackdump(x));
llSay(0,"Get of nonexistent key: y = dictGetElement(x, , 6)"); y = dictGetElement(x, "", 6); llSay(0,"y: "+stackdump(y)); }
} </lsl>