Jump to content

Sorting one list whilst keeping indexed data from another list


Beach Nightfire
 Share

You are about to reply to a thread that has been inactive for 337 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

Hello,

I have spent days trying to get(what i think) is a simple task done,

I have two lists. List A is text data whilst list B is vectors. When the two list are added to by external data feeds, they are fed using the same index number.

I am trying normal C++ type logic and not getting anywhere. I have tried examples on here, however a lot have errors.

psudo code is

List A += "Some text";

List B += a vector;

I have spent days on this, so i am not being lazy.

 

TIA

Link to comment
Share on other sites

1 minute ago, Love Zhaoying said:

You could use a 2-stride list: one stride is the vector, one stride is the text. 

Then, use the function llListSortStrided() to sort the list.

https://wiki.secondlife.com/wiki/LlListSortStrided

About Strided lists: 

https://wiki.secondlife.com/wiki/Category:LSL_List#Strided_lists

Thanks for the reply. To be honest, i looked at the strided list on the wiki and i was lost. The example didnt make sense. I will have another look. Cheers.

Just to be clear, the sort is in alphabetical order and keep the vectors linked to the respective alphabetic character.

Link to comment
Share on other sites

4 minutes ago, Beach Nightfire said:

Thanks for the reply. To be honest, i looked at the strided list on the wiki and i was lost. The example didnt make sense. I will have another look. Cheers.

Just to be clear, the sort is in alphabetical order and keep the vectors linked to the respective alphabetic character.

A "stride" is a "slice" like this:

First stride = Vector, List element 0 should contain a vector - if that's what you put in it.

Second stride = Text, List element 1 should contain a the Text - if that's what you put in it.

So, you'd put one type of thing in elements 0, 2, 4.. and another type of thing in elements 1, 3, 5..

All the LSL "strided list" functions do in this example, is to sort (or whatever) on every 1st or 2nd List entry. 

  • Like 1
Link to comment
Share on other sites

4 minutes ago, Love Zhaoying said:

A "stride" is a "slice" like this:

First stride = Vector, List element 0 should contain a vector - if that's what you put in it.

Second stride = Text, List element 1 should contain a the Text - if that's what you put in it.

So, you'd put one type of thing in elements 0, 2, 4.. and another type of thing in elements 1, 3, 5..

All the LSL "strided list" functions do in this example, is to sort (or whatever) on every 1st or 2nd List entry. 

I have two separate lists one list has text the other list has vectors. Maybe you are explaining correctly and i am taking it as one list with a mix of strings and vectors.

 

  • Like 1
Link to comment
Share on other sites

3 minutes ago, Beach Nightfire said:

I have two separate lists one list has text the other list has vectors. Maybe you are explaining correctly and i am taking it as one list with a mix of strings and vectors.

 

Yep, I was just giving a way to do it with a single list. 

  • Like 1
Link to comment
Share on other sites

Now that we have llListSortStrided, strided lists really are the only sane option when related lists need to be sorted, but if you absolutely must use 2 separate lists:

  1. 'splice in' index integers to the sorting list: ["Oranges","Bananas","Apples"] -> ["Oranges",0,"Bananas",1,"Apples",2];
  2. Sort the list by the first element with a stride of 2: ["Apples",2,"Bananas",1,"Oranges",0];
  3. Cherry pick together items of the list to sort: l2l(list l, integer n){ llList2List(l,n,n) } list sorted = l2l(l,2) + l2l(l,1) + l2l(l,0);

Alternatively, splice in elements of the list to sort in step 1, then pull them out in step 3 with llList2ListStrided or the newer and more sane llList2ListSlice. Using indexes just generalizes better for more than 2 lists.

Edited by Quistess Alpha
  • Like 1
  • Thanks 1
Link to comment
Share on other sites

To clarify: if your data is in 2 separate lists and you plan on sorting, one list would need an entry that relates to the other list (effectively, a "stride" that is the index into the second list).

Alternatively, you could sort one list into a third list, then if an entry is selected search the original (unsorted) list for the entry# (which matches the entry# in the second list if you keep them in sync).

  • Like 1
Link to comment
Share on other sites

Thanks all. I think i am relating to using relational databases in RL. Ie sorting using a key.

THank you all for your time :)

 

I had two lists as i read you cant store much in a single list. I have 300 elements to save

As a lot of information can be 10 years old, maybe the limitation isnt there. 

Lets assume i have one list. With two elements

ie

index 0  ["some string of some sort", <123.45,123.45,123.45>]

index 1  ["some other string", <123.45,123.45,123.45>]

if i sort, i only wanted to sort based on the first element

 

Edited by Beach Nightfire
  • Like 1
Link to comment
Share on other sites

2 hours ago, Beach Nightfire said:

I had two lists as i read you cant store much in a single list. I have 300 elements to save

Lists can be arbitrarily long, up to the amount of memory the script has available. Splitting the information into 2 lists doesn't save any memory.

For a single 'strided list' with 2 things per pair, and you want to sort them alphabetically by name:

default
{   state_entry()
    {   list myList = ["A...",<1,1,1>,"D...",<2,2,2>,"C...",<7,7,7>,"B....",<3,3,3>];
        list myListSortedOld = llListSort(myList,2 /*# elements per stride*/,TRUE /*alphabet order: a,b,c...*/ ); 
        // expect myListSortedOld == [A... 1,1,1 B... 3,3,3 etc.
        list myListSortedNew = llListSortStrided(myList,2 /*#elements per stride*/,0 /*sort based on the 1st element of each stride*/,TRUE /*ascending order*/);
        // expect myListSortedOld == myListSortedNew.
        llOwnerSay(llList2CSV(myList)+"\n"+llList2CSV(myListSortedOld)+"\n"+llList2CSV(myListSortedNew) );
    }
} // retroactively embedded into a wrapper script.

If anyone who has wiki access reads this, the wiki for https://wiki.secondlife.com/wiki/LlListSortStrided has a typo: the description for the 'stride_index' parameter is the description of the 'ascending' parameter, which is undescribed. It should be something like:

Quote
• list src List to be sorted.  
• integer stride number of entries per stride, if less than 1 it is assumed to be 1  
• integer stride_index the index of the stride by which to sort; if 0, this function behaves as llListSort();  
• integer ascending   if TRUE then the sort order is ascending, otherwise the order is descending.

or so.

Edited by Quistess Alpha
  • Thanks 2
Link to comment
Share on other sites

36 minutes ago, Quistess Alpha said:

Lists can be arbitrarily long, up to the amount of memory the script has available. Splitting the information into 2 lists doesn't save any memory.

For a single 'strided list' with 2 things per pair, and you want to sort them alphabetically by name:

list myList = ["A...",<1,1,1>,"D...",<2,2,2>,"C...",<7,7,7>,"B....",<3,3,3>];
list myListSortedOld = llListSort(myList,2 /*# elements per stride*/,TRUE /*alphabet order: a,b,c...*/ ); 
// expect myListSortedOld == [A... 1,1,1 B... 3,3,3 etc.
list myListSortedNew = llListSortStrided(myList,2 /*#elements per stride*/,0 /*sort based on the 1st element of each stride*/,TRUE /*ascending order*/);
// expect myListSortedOld == myListSortedNew.
llOwnerSay(llList2CSV(myList)+"\n"+llList2CSV(myListSortedOld)+"\n"+llList2CSV(myListSortedNew) );

If anyone who has wiki access reads this, the wiki for https://wiki.secondlife.com/wiki/LlListSortStrided has a typo: the description for the 'stride_index' parameter is the description of the 'ascending' parameter, which is undescribed. It should be something like:

or so.

 

Is this code meant to work? I get syntax error on line 2. I was just going to play with this. Thanks

Link to comment
Share on other sites

1 minute ago, Beach Nightfire said:

Is this code meant to work? I get syntax error on line 2. I was just going to play with this. Thanks

Hmm. @Quistess Alpha, I was pretty sure you only meant to provide "example" code; but can you call llListSortStrided() at the same time you declare the list variable? Or is the issue the embedded comments?

  • Like 1
Link to comment
Share on other sites

14 minutes ago, Beach Nightfire said:

Is this code meant to work? I get syntax error on line 2. I was just going to play with this. Thanks

It fails on line 2 because you can't run functions outside of an event. Copy-paste it into the state_entry or touch_start sections of the standard example script and it runs as expected. ETA: or re-copy paste from the above post which I edited.

10 minutes ago, Love Zhaoying said:

can you call llListSortStrided() at the same time you declare the list variable?

You can (because they're different lists).

Edited by Quistess Alpha
  • Thanks 2
Link to comment
Share on other sites

6 minutes ago, Quistess Alpha said:
15 minutes ago, Love Zhaoying said:

can you call llListSortStrided() at the same time you declare the list variable?

You can (because they're different lists).

Thanks, it's hard to remember what you can/can't do while declaring a variable besides assign its value to a constant.

  • Like 1
Link to comment
Share on other sites

26 minutes ago, Love Zhaoying said:

Thanks, it's hard to remember what you can/can't do while declaring a variable besides assign its value to a constant.

The only thing you can't do is evaluate some calculation or result outside of an event/function scope. everything else is allowed:

integer z = 0;
integer test = z; // asignment to a variable is allowed. (but probably bad practice)
// integer test2 = test = 1; // assignment to the result of an assignment is disallowed evaluation.
// integer c = d = 2; // also not allowed, variables need to be declared individually in LSL.
default
{   state_entry(){}
}

 

  • Thanks 2
Link to comment
Share on other sites

5 hours ago, Beach Nightfire said:

I had two lists as i read you cant store much in a single list. I have 300 elements to save

As a lot of information can be 10 years old, maybe the limitation isnt there. 

Well, it's still limited (to 64KB, total of code and data). Better than it was many years ago (16KB), but still you could have a problem with 300 arbitrary strings and 300 vectors, depending on the average length of those strings. As @Quistess Alpha says though, using separate lists wouldn't save any memory, so if all those strings and vectors fit now, they'll fit in a combined list, too. The point is, if those strings ever get much longer, the script is going to fail.

If it's going to get that big, it's probably easiest to use external data storage. You can squeeze a bit extra by compressing the vectors and/or using linkset data instead of script memory (llLinksetDataListKeys returns an alpha-sorted list) but that's still subject to failure if those strings get even longer. There are other workarounds, including sorting across multiple memory scripts, but they get very complicated—complicated enough to want to assess why these data are being processed in a script at all.

  • Like 1
Link to comment
Share on other sites

Once again, Thank you all. 

I will set a limit on data. delete places in the list if new data comes in under the same name.

I tired the sorting, and using this line

list myListSortedNew = llListSortStrided(myList,2 /*#elements per stride*/,0 /*sort based on the 1st element of each stride*/,TRUE /*ascending order*/);
With changes to suit my lists, works well/

Once again, thank you for your time.

  • Like 1
  • Thanks 1
Link to comment
Share on other sites

2 hours ago, Quistess Alpha said:

experience KVP can be nice, especially now that LinksetData makes the idiom of forcing it into a synchronous wrapper move viable.

Yes, but in this case I kinda got hung up on how to sort more KVP data than can fit in the LinksetData. We can't assume any particular ordering of results from llKeysKeyValue, right? I bottomed-out with the prospect of writing a sort routine directly on asynchronous Experience KVP (and storing an index somewhere, perhaps LinksetData), but I may have missed a tidier approach.

Link to comment
Share on other sites

13 minutes ago, Qie Niangao said:

Yes, but in this case I kinda got hung up on how to sort more KVP data than can fit in the LinksetData. We can't assume any particular ordering of results from llKeysKeyValue, right? I bottomed-out with the prospect of writing a sort routine directly on asynchronous Experience KVP (and storing an index somewhere, perhaps LinksetData), but I may have missed a tidier approach.

Are these options to try based on the original post? 

  • Like 1
Link to comment
Share on other sites

19 minutes ago, Beach Nightfire said:

[Experience KVP and Linkset data] Are these options to try based on the original post? 

Probably not, given the clarification that you're only storing around 300*2 elements, and you don't need to uncheck the 'mono' checkbox in your script for some arcane reason.

  • Like 2
Link to comment
Share on other sites

8 hours ago, Beach Nightfire said:

Are these options to try based on the original post? 

As Quistess said, probably not. The question only even arises because each individual string could be very large, if it can be any string. In contrast, if we know they'll be names of objects, for example, it will necessarily be shorter than the bound on that, which is only 63 bytes. Assuming the rest of the script isn't gobbling up lots of memory, a list of three hundred object names and vectors should fit. Below is a useless little script to make sure


list theList;

default
{
    state_entry()
    {
        integer i = 301;
        while (--i)
        {
            string thisString;
            integer iChar = 64;
            while (--iChar)
                thisString += llChar((integer)llFrand(90.0)+33); // some simple low-Unicode characters
            theList += [ thisString, < llFrand(256.0), llFrand(256.0), llFrand(256.0)> ];
        }
        llOwnerSay("Memory: "+(string)llGetUsedMemory()+" Used, "+(string)llGetFreeMemory()+ " Free");
    }
}

So absolute worst case for 300 object names and vectors appears to be under 56K, leaving maybe 10K for code and other variables.

(Note: all the fussing with making new, random strings for each test element is because repeated identical strings can be stored with big, unrepresentative savings. The reason to test at all is that lists and even strings use a little extra for overhead, and different amounts of overhead for global and local variables. Attempts to quantify the various overheads are… messy.)

  • Like 1
Link to comment
Share on other sites

18 minutes ago, Beach Nightfire said:

Not sure what this means? Was it mentioned? The guides do say leave it ticked, yet you say MONO is arcane?

by arcane it is meant that unticking the box is arcane. Ticked means LSL Mono (64k). Unticked means LSO the original Linden 16k compiler (arcane) from back in the day

Edited by elleevelyn
  • Like 2
Link to comment
Share on other sites

If the LinksetData sorting issue with "Find Keys" was fixed (I keep forgetting), then it could be used for an automatically sorted "list". Each "sorted element" would be a LinksetData Key, and "non sorted element" a LinksetData Value..

 

* Disclaimer: I now use LInksetData plus JSON for pretty much everything instead of lists..

Edited by Love Zhaoying
  • Thanks 1
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 337 days.

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
 Share

×
×
  • Create New...