Xiija Posted February 23, 2023 Share Posted February 23, 2023 (edited) Has anyone come up with any inventive ways to do pointers in LSL ? I need to cycle thru a list of lists ! lol currently dealing with this grunginess... integer x; integer len = llGetListLength( Jazz ); for( x = 0; x < len; ++x ) { string node = (string)(x+1); string url = llList2String(Jazz,x); webStations = llJsonSetValue (webStations, ["Jazz", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Jazz", "NUM-" + node, "URL"], url); } // ==================== integer x2; integer len2 = llGetListLength( Rock ); for( x2 = 0; x2 < len2; ++x2 ) { string node = (string)(x2+1); string url = llList2String(Rock,x2); webStations = llJsonSetValue (webStations, ["Rock", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Rock", "NUM-" + node, "URL"], url); } // ======================== integer x3; integer len3 = llGetListLength( Reggae ); for( x3 = 0; x3 < len3; ++x3 ) { string node = (string)(x3+1); string url = llList2String(Reggae,x3); webStations = llJsonSetValue (webStations, ["Reggae", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Reggae", "NUM-" + node, "URL"], url); } // ================================ integer x4; integer len4 = llGetListLength( Country ); for( x4 = 0; x4 < len4; ++x4 ) { string node = (string)(x4+1); string url = llList2String(Country,x4); webStations = llJsonSetValue (webStations, ["Country", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Country", "NUM-" + node, "URL"], url); } Edited February 24, 2023 by Xiija Link to comment Share on other sites More sharing options...
Love Zhaoying Posted February 23, 2023 Share Posted February 23, 2023 Yes, but I use JSON. In my case, a "pointer" is a unique value that identifies a "data instance" that I store in JSON. I use it as a "key" in some JSON, then as a "pointer" in other JSON to that "key" data. You could do the same with lists. I use GUID's. Those are big, you could use something else depending on your needs. Link to comment Share on other sites More sharing options...
primerib1 Posted February 24, 2023 Share Posted February 24, 2023 (edited) 5 hours ago, Xiija said: Has anyone come up with any inventive ways to do pointers in LSL ? I need to cycle thru a list of lists ! lol currently dealing with this grunginess... integer x; integer len = llGetListLength( Jazz ); for( x = 0; x < len; ++x ) { string node = (string)(x+1); string url = llList2String(Jazz,x); webStations = llJsonSetValue (webStations, ["Jazz", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Jazz", "NUM-" + node, "URL"], url); } // ==================== integer x2; integer len2 = llGetListLength( Rock ); for( x2 = 0; x2 < len2; ++x2 ) { string node = (string)(x2+1); string url = llList2String(Rock,x2); webStations = llJsonSetValue (webStations, ["Rock", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Rock", "NUM-" + node, "URL"], url); } // ======================== integer x3; integer len3 = llGetListLength( Reggae ); for( x3 = 0; x3 < len3; ++x3 ) { string node = (string)(x3+1); string url = llList2String(Reggae,x3); webStations = llJsonSetValue (webStations, ["Reggae", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Reggae", "NUM-" + node, "URL"], url); } // ================================ integer x4; integer len4 = llGetListLength( Country ); for( x4 = 0; x4 < len4; ++x4 ) { string node = (string)(x4+1); string url = llList2String(Country,x4); webStations = llJsonSetValue (webStations, ["Country", "NUM-" + node ], node); webStations = llJsonSetValue (webStations, ["Country", "NUM-" + node, "URL"], url); } Well, truth be told, I see no problems with your implementation. You might be able to reuse the variables x and len, since they doesn't seem to be used outside the for() loop. An alternative will be to leverage LSD, say by encoding the key as "_d:mus:" + genre + "-" + node Using LSD, you gain 2 benefits (which may or may not be applicable to your use case): One, it is immediately persistent (it will survive llResetScript() as well!) And two, it is globally available immediately, not only for the script in which the LSD KVP was made, but also for all other scripts part of the same linkset. If your script is pushing the limits of the 64 KiB space, then it might be a good idea to just split the script into two, communicating between them using link messages and LSD. Edited February 24, 2023 by primerib1 Link to comment Share on other sites More sharing options...
elleevelyn Posted February 24, 2023 Share Posted February 24, 2023 examples showing the principle of using indexing as "pointers" in a list are here: On 4/13/2019 at 8:16 PM, Mollymews said: this one is a little bit awkward to do in LSL as we don't have memory pointers, structs or classes. We can tho store a tree in a list (or a string) and work with it as a tree. as wrote the problem case asks us to serialise a tree structure to a string then deserialise the string to a tree. Effectively saving and restoring it from say a file or notecard. In the LSL case because we can use a list, then save/restore can be done simply with llDumpList2String and ParseString2List this said, trees are useful for stuff like paths in quest/games, nested menu systems, etc etc here is one way to use a list to manage an unbalanced binary tree according to the principles contained in the problem case. This method traverses the tree using a non-recursive stack method. A depth-first traversal. Non-recursive stack methods (and queue methods for breadth-first trees) can be a little bit easier to follow in their code construction. Probably also easier to visualise their memory usage in this traverse method the path is: go left, until cannot go any further left, then go right, when cannot go any further right then go back. When we start at the root of the tree we will end up back at the root after visiting every child node at least once. we define a tree node to be 4 adjacent list elements. (similar to a stride) Element 1 : pointer to the parent of the node. The root node is its own parent (0) Element 2 : pointer to the right child node. Pointer is 0 when there is no child node Element 3 : pointer to the left child node. Pointer is 0 when there is no child node Element 4 : data value stored in the node example code: //list index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 list tree = [0,8,4,"Root", 0,0,12,"A Node", 0,20,16,"B Node", 4, 0, 0,"C Node", 8, 0, 0,"E Node", 8, 0, 0,"F Node"]; // the traversal path as wrote for this tree is: > Root > A Node > C Node > A Node > Root > B Node > E Node > B Node > F Node > B Node > Root // other nodes can be added (or removed) as you like. The list order of nodes is unimportant, whats important is that node pointer values do point to a valid list index list stack; stackPush(integer ptr) { // add a child node to the stack stack += llList2List(tree, ptr, ptr + 3); } integer stackPop() { integer ptr = llList2Integer(stack, -4); // get the parent node of the topmost node stack = llDeleteSubList(stack, -4, -1); // remove the topmost node from the stack return ptr; } integer stackPeek() { integer idx = -2; integer ptr = llList2Integer(stack, idx); if (!ptr) // if no left child then get right child if any ptr = llList2Integer(stack, --idx); if (ptr) // signal that we have taken this path stack = llListReplaceList(stack, [0], idx, idx); return ptr; // when ptr == 0 then there is no child } default { state_entry() { string path; integer node = 0; // begin at root stackPush(node); while (llGetListLength(stack)) { path += (" > " + llList2String(tree, node + 3)); node = stackPeek(); if (node) // is a child node stackPush(node); else node = stackPop(); // node is now the parent node } llSay(0, path); } } and here On 10/28/2021 at 12:01 AM, Mollymews said: a conversation about sparse arrays here led to the topic about the inefficiencies of using strings to store variable length records in the form list table = [ "a|b|c", "d|e", "f|g|h|i", "y|z" ] which prompted me to have a play. A example of a general purpose 2-dimensional sparse array as a table with variable length records that preserve list element types i think is ok, but if it breaks I will fix it if you let me know fix: ACTION_FIND. Was finding last occurrence of pattern, not the first /* example of general purpose sparse array table with helper functions in row column format where a row (sublist) can have any number of elements (columns) row indexing is 0-based same as list for negative indexing use: rowcount-1, rowcount-2,rowcount-3, etc usage examples in touch_start below fix: ACTION_FIND. Was finding last occurence of pattern, not the first placed in public domain */ integer ACTION_APPEND = 0; // table += [some,data] integer ACTION_INSERT = 1; // llListInsertList integer ACTION_REPLACE = 2; // llListReplaceList integer ACTION_DELETE = 3; // llDeleteSubList integer ACTION_FIND = 4; // llListFindList list table; // data table list rows; // pointers to 1st element of each row integer currentrow = -1; // updated on action. is -1 when table is empty integer rowcount; // = length of list rows integer tablecount; // = length of list table. - list fetch(integer row) // llList2List { // fetch/get a list of elements (columns) in row if ((row > -1) & (row < rowcount)) { integer e = tablecount - 1; if (row < rowcount - 1) e = llList2Integer(rows, row + 1) - 1; return llList2List(table, llList2Integer(rows, row), e); } else return []; // return empty when row is out of bounds. bounds in [0 .. rowcount-1] } integer action(integer act, integer row, list data) { // default to -1 fail / not found. OnSuccess return currentrow integer result = -1; if (act == ACTION_APPEND) { if (data) { rows += [tablecount]; table += data; tablecount = llGetListLength(table); result = currentrow = ++rowcount; } } else if ((row > -1) & (row < rowcount)) // row in bounds else fail { integer r = llList2Integer(rows, row); integer e = tablecount - 1; if (act == ACTION_DELETE) { if (row < rowcount - 1) e = llList2Integer(rows, row + 1) - 1; else --currentrow; table = llDeleteSubList(table, r, e); rows = llDeleteSubList(rows, row, row); --rowcount; e = -(e - r + 1); result = currentrow; } else if (data) // fails when data is empty list { if (act == ACTION_INSERT) { table = llListInsertList(table, data, r); rows = llListInsertList(rows, [r], row++); ++rowcount; e = llGetListLength(data); result = currentrow; } else if (act == ACTION_REPLACE) { if (row < rowcount - 1) e = llList2Integer(rows, ++row) - 1; table = llListReplaceList(table, data, r, e); e = llGetListLength(data) - 1 - (e - r); result = currentrow; } else if (act == ACTION_FIND) { if (row) // can be memory expensive, but it does enable findNext e = llListFindList(llDeleteSubList(table, 0, r - 1), data); else // row = 0. search entire table e = llListFindList(table, data); if (~e) // not found when e = -1 { // get row number, disallow when found data pattern crosses row boundary e += r; integer continue = TRUE; for (r = row; (r < rowcount) & continue; ++r) { integer ee = tablecount - 1; if (r < rowcount - 1) ee = llList2Integer(rows, r + 1); if ((e >= llList2Integer(rows, r)) & (e < ee)) { // note fetch is called. This could be calculated result = llListFindList(fetch(r), data); if (~result) { // found wholely in row result = currentrow = r; continue = FALSE; } } } } } } if (act != ACTION_FIND) { // update rows pointers and tablecount for (r = row; r < rowcount; ++r) rows = llListReplaceList(rows, [llList2Integer(rows, r) + e], r, r); tablecount = llGetListLength(table); } } // return currentrow after action // return -1 when row out of bounds or not found return result; } emptyTable() { // empty table and reset supportives table = []; rows = []; currentrow = -1; rowcount = 0; tablecount = 0; } default { touch_start(integer num_detected) { llOwnerSay("BEGIN"); emptyTable(); // fill with some data. Data can be any type. // little strings used to easier see what is happening action(ACTION_APPEND, 0, ["aa", "ab", "ac"]); action(ACTION_APPEND, 0, ["ba", "bb"]); action(ACTION_APPEND, 0, ["ca"]); action(ACTION_APPEND, 0, ["da", "db"]); action(ACTION_APPEND, 0, ["ea", "eb", "ec"]); action(ACTION_APPEND, 0, ["fa", "fb"]); llOwnerSay("append: [" + llDumpList2String(table, ",") + "]"); llOwnerSay("rows: [" + llDumpList2String(rows, " ") + "]"); action(ACTION_DELETE, 1, []); llOwnerSay("delete row 1: [" + llDumpList2String(table, ",") + "]"); llOwnerSay("rows: [" + llDumpList2String(rows, " ") + "]"); action(ACTION_INSERT, 3, ["ma", "mb", "mc"]); llOwnerSay("insert new row 3: [" + llDumpList2String(table, ",") + "]"); llOwnerSay("rows: [" + llDumpList2String(rows, " ") + "]"); action(ACTION_REPLACE, 0, ["ya", "yb"]); action(ACTION_REPLACE, rowcount - 1, ["xa"]); llOwnerSay("replace row 0 and last row: [" + llDumpList2String(table, ",") + "]"); llOwnerSay("rows: [" + llDumpList2String(rows, " ") + "]"); list elements = fetch(3); llOwnerSay("fetch elements in row 3: [" + llDumpList2String(elements, ",") + "]"); // the pattern to find, can be any number of elements integer i = action(ACTION_FIND, 0, ["db"]); llOwnerSay("find row for [db] in entire table. Row = " + (string)i); i = action(ACTION_FIND, 4, ["da", "db"]); llOwnerSay("find row for [da,db] from row 4. Row = Not Found = " + (string)i); i = action(ACTION_FIND, 0, ["db","ma"]); llOwnerSay("find cross boundary fail for [da,ma]. Row = Not Found = " + (string)i); llOwnerSay("END"); } } Link to comment Share on other sites More sharing options...
Xiija Posted March 1, 2023 Author Share Posted March 1, 2023 (edited) thanx all for the helps, I used csv and could do both an example for anyone looking for list pointers... string webStations; list jazz_a; list jazz_b; default { state_entry() { // JSON webStations = llList2Json( JSON_OBJECT, [] ); // or json2list from web jazz_a = [ "https://breakz-high.rautemusik.fm/?ref=radiobrowserinfo", "https://jam-high.rautemusik.fm/?ref=radiobrowser", "https://mixtapes.superstreams.de/", "https://mixtapes.electronicssounds.com/", "http://stream.laut.fm/ruffneck-smille?ref=radiode", "http://o89fm.de:8000/main", "https://stream.0nlineradio.com/latin?ref=radiobrowser", "https://stream.0nlineradio.com/remix?ref=radiobrowser", "http://strm112.1.fm/reggae_mobile_mp3" ]; jazz_b = [ "2-https://breakz-high.rautemusik.fm/?ref=radiobrowserinfo", "2-https://jam-high.rautemusik.fm/?ref=radiobrowser", "2-https://mixtapes.superstreams.de/", "2-https://mixtapes.electronicssounds.com/", "2-http://stream.laut.fm/ruffneck-smille?ref=radiode", "2-http://o89fm.de:8000/main", "2-https://stream.0nlineradio.com/latin?ref=radiobrowser", "2-https://stream.0nlineradio.com/remix?ref=radiobrowser", "2-http://strm112.1.fm/reggae_mobile_mp3" ]; string ja = llList2CSV(jazz_a); string jb = llList2CSV(jazz_b); webStations = llJsonSetValue (webStations, ["MAIN", "Jazz_a" ], ja); webStations = llJsonSetValue (webStations, ["MAIN", "Jazz_b" ], jb); string urls = llJsonGetValue (webStations, ["MAIN", "Jazz_a" ]); llOwnerSay("\ndata: " + urls); list j1 = llCSV2List( urls ); llOwnerSay("\nJSON data check: " + llList2String( j1, 0) ); list jmain = ["Jazz_a", "Jazz_b"]; // ================================= store list names as strings string jINDX = llList2String( jmain,0); // ============================= get a string name string main = llJsonGetValue (webStations, [ "MAIN" , jINDX ]); // ==== call JSON string/list with a string name llOwnerSay("\nMain:\n" + main + "\n Touch to get LsD data"); } touch_start(integer total_number) { // LsD string j1 = llList2CSV(jazz_a); string j2 = llList2CSV(jazz_b); llLinksetDataWrite( "j1" ,j1 );//====================================== make a key string llOwnerSay( "\nLsD data check: \n" + llLinksetDataRead("j1")); //====== check it is stored list jmain = ["j1", "j2"]; // ==================================== store key names as list of strings string jINDX = llList2String( jmain,0); // ========================= get a string name llOwnerSay( "\n J data: \n" + llLinksetDataRead( jINDX )); // ==== call LsD key with a string name list jlist_1 = llCSV2List( llLinksetDataRead( jINDX ) ); // ===== seperate string into csv llOwnerSay("\nLsD first entry:\n " + llList2String( jlist_1, 0) ); } } Edited March 1, 2023 by Xiija Link to comment Share on other sites More sharing options...
Recommended Posts
Please take a moment to consider if this thread is worth bumping.
Please sign in to comment
You will be able to leave a comment after signing in
Sign In Now