Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Yet Another Multidimensional Array Script

Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
06-08-2005 23:35
Hey all, I ran into another problem where multidimensional arrays would have *really* helped, so I decided to spend another day on finding out a way to stuff the data into LSL's list structure.

So here goes:
CODE

// Generates a random string of length len
// from the characters passed to it.
string randomStr(string chars, integer len) {
integer numChars = llStringLength(chars);
string ret;
integer i;
for (i = 0; i < len; i++) {
integer randIndex = llFloor(llFrand(numChars));
ret += llGetSubString(chars, randIndex, randIndex);
}
return ret;
}

string SEPERATOR_CHARS = "`~!@#$%^&*()-_+[]{}\|'\";/?.>,<";
integer SEPERATOR_LEN = 3;
string dumpList2String(list src) {
// Generate a seperator not present in any of the
// elements in the list.
string chars = (string) src; // Squashes all elements together.
string seperator;
do {
seperator = randomStr(SEPERATOR_CHARS, SEPERATOR_LEN);
} while (llSubStringIndex(chars, seperator) != -1);
return seperator + llDumpList2String(src, seperator);
}

list parseStringKeepNulls(string src) {
// The seperator should be the first SEPERATOR_LEN
// characters in the string.
return llParseStringKeepNulls(llDeleteSubString(src, 0, SEPERATOR_LEN - 1),
[llGetSubString(src, 0, SEPERATOR_LEN - 1)], []);
}

string NULL = "";
list listReplaceList(list dest, list src, integer start, integer ensureLocation) {
if (ensureLocation && llGetListEntryType(dest, start - 1) == TYPE_INVALID) {
// Fill with nulls until we get to the starting position.
integer len = llGetListLength(dest);
for (len = llGetListLength(dest); len < start; ++len) {
dest += NULL;
}
}
return llListReplaceList(dest, src, start, start + llGetListLength(src) - 1);
}

list getElementAt(list array, list index){
if (index == [])
return array;
integer numIndicies = llGetListLength(index);
list src = array;
integer i;
for (i = 0; i < numIndicies - 1; ++i) {
integer listIndex = llList2Integer(index, i);
string element = llList2String(src, listIndex);
if (llGetSubString(element, 0, 0) == "l")
element = llDeleteSubString(element, 0, 0);
src = parseStringKeepNulls(element);
}
string element = llList2String(src, llList2Integer(index, -1));
if (llGetSubString(element, 0, 0) == "l") {
// Caller is retreiving a dimension.
return parseStringKeepNulls(llDeleteSubString(element, 0, 0));
} else {
return [element];
}
}

// To set an element, we need to extract
// each list starting from where exactly the
// new data will be. In a set of russian dolls, this
// would be equivelant to grabbing the littlest one
// first. then gradually adding back on the layers over it.
// I think its easiest to do this recursively.
list setElementAt(list array, list data, list index) {
string element;
if (llGetListLength(data) > 1) {
// Data is a new dimension:
element = "l" + dumpList2String(data);
} else {
// Data is a single element
element = llList2String(data, 0);
}
if (llGetListLength(index) > 1) {
// index is in the form [a,b,c,d]
// here, we grab the list that d is in.
list containerIndex = llDeleteSubList(index, -1, -1);
list dest = getElementAt(array, containerIndex);
integer listIndex = llList2Integer(index, -1); // Grab d
dest = listReplaceList(dest, [element], listIndex, TRUE); // replace the element in d's list.
// Make sure the recursion treats the container like a list, not an element.
if (llGetListLength(dest) == 1)
dest += "";
return setElementAt(array, dest, containerIndex);
} else {
return listReplaceList(array, [element], llList2Integer(index, 0), TRUE);
}
}

// And a sample usage:
default {
state_entry() {
llOwnerSay("Compiled.");
list array;
array = setElementAt(array, ["fool", "barn"], [0, 0]);
array = setElementAt(array, ["ACK", "FARN!", "MER!"], [0, 0, 1]);
array = setElementAt(array, ["blah"], [0, 1]);
array = setElementAt(array, ["garage", "flack"], [1]);
array = setElementAt(array, [], [0, 0, 1]);
llOwnerSay("array == [" + llList2CSV(array) + "]");
llOwnerSay("[" + llList2CSV(getElementAt(array, [1, 0])) + "]");
}
}


Features:
1. Dynamic arrays: No need to specify dimension length!
2. "Ragged" arrays: Its truly lists in lists - any size list can be put into any other list.

Testing welcome :D

... and before you say "didn't you do this already?" -- eh, nevermind :)
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
06-18-2005 09:53
/15/ea/49630/1.html
_____________________
i've got nothing. ;)
Dragon Steele
Artist/conservationist
Join date: 3 Jan 2005
Posts: 183
06-19-2005 19:09
Ok call me Dumb BUt What does this Multidimensional Array do and WHat would i use it for? :confused: :)
_____________________
Boycot the spam farms and the ads on them. Ban the spamers from your land. Look for the clocktower network for a blacklist to put on you land that is grid wide.
Strife Onizuka
Moonchild
Join date: 3 Mar 2004
Posts: 5,887
06-19-2005 20:56
It's so you can store lists in lists.

here is my comment i posted on the LSL wiki on
From: someone

There is a problem with generating seperators of 3 or more characters.

say your packing
["---AB","BA---"]
and the seperator comes up as
"ABA"
When you depack you will get
["---","A","---"]
The fastest solution is to make sure your first and last characters are not used any where else in the string

CODE

string randomStr(string chars, integer len) {
integer numChars = llStringLength(chars);
integer first = (integer)(llFrand(numChars));
if(len > 1)
{//if (numChars < 2 + (len > 2)){llOwnerSay("error: string too short"); list a = [[""]];}
integer last;
do
last = (integer)(llFrand(numChars));
while(last == first);
string ret;
integer i;
integer randIndex;
numChars -= 2;
for (i = 2; i < len; i++) {
do
randIndex = (integer)(llFrand(numChars));
while(last == randIndex || first == randIndex);
ret += llGetSubString(chars, randIndex, randIndex);
}
return llGetSubString(chars, first, first) + ret + llGetSubString(chars, last, last);
}
return llGetSubString(chars, first, first);
}

_____________________
Truth is a river that is always splitting up into arms that reunite. Islanded between the arms, the inhabitants argue for a lifetime as to which is the main river.
- Cyril Connolly

Without the political will to find common ground, the continual friction of tactic and counter tactic, only creates suspicion and hatred and vengeance, and perpetuates the cycle of violence.
- James Nachtwey