Jump to content

Collating the data in a simple strided list


Ares Halostar
 Share

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

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

Recommended Posts

I have a list of data that basically gives an integer, and avatar name.

The integer is the result of how many prims an avatar may have on a given parcel.  

But my avatar and others are repeated in the list several times and with different amounts (as I own several parcels on that region) ie:

1367, Ares Halostar, 456, Drongo Bonk, 325, Ares Halostar, 345, Mr Zonk, 567, Drongo Bonk

My name appears twice, as does another, but I want to total the integers and create a new list:

1692, Ares Halostar, 1023, Drongo Bonk, 345, Mr Zonk.

Lists always do my head in, even though this is a simple 2 strided list.

Please can someone work out a quick routine for me to use ?

 

Thanks in advance.

Link to comment
Share on other sites

I'd do something like... strided sort the list, and now that you know all the same names are following each other you can just peek ahead/back to combine the values until the name changes. Doing it by modifying a list in-place, it's easiest to loop backwards so you don't break indexes that you're going to use. 

list test = [19, "epsilon", 37, "alpha", 8, "gamma", 14, "beta", 99, "alpha", 1, "gamma"];
// sort list, stride 2, element #1 (so 2nd element)
test = llListSortStrided(test, 2, 1, TRUE);
// start from 2nd last element pair
integer i = (llGetListLength(test)/2)-1;
integer value;
string name;
while(i >= 0) {
    value = llList2Integer(test, i*2);
    name = llList2String(test, i*2+1);
    // peek at the following name; if equal, add values and delete following element
    if(llList2String(test, i*2+3) == name) {
        value += llList2Integer(test, i*2+2);
        test = llDeleteSubList(test, i*2+2, i*2+3);
        test = llListReplaceList(test, (list)value, i*2, i*2);
    }
    --i;
}
llOwnerSay(llList2CSV(test)); // "136, alpha, 14, beta, 19, epsilon, 9, gamma"

 

Link to comment
Share on other sites

1 hour ago, Ares Halostar said:

But my avatar and others are repeated in the list several times and with different amounts (as I own several parcels on that region) ie:

1367, Ares Halostar, 456, Drongo Bonk, 325, Ares Halostar, 345, Mr Zonk, 567, Drongo Bonk

How do you get this data right now?

Frionil's suggestion works for cleaning up the data, but maybe we can get it in the right format before it needs to be sorted.

Link to comment
Share on other sites

While this works in SL, I need it to work in Opensim as well, and llListSortStrided is not supported as yet.

Basically what I am trying to achieve, is to scan a region's parcels, and find out how many prims the avatars are using on that region.

I will attach the code that I am experimenting with now.

list    gListCountsAndOwners;       // Sorted list count+owner pairs
list    gListNamesAndCounts;        // List of owner names + prim counts
integer gOffset;
integer gIndex;
key     gDataserverID;
integer gListLength;
list gPrclID; 
integer gTotPrims;
integer gNUM; 
float gX;
float gY;  
list NameList;
CalcPrims(vector Loc)
{
    list TempList = llGetParcelPrimOwners(Loc);
    gListLength= llGetListLength(TempList);      
    if (!gListLength)
    {
        llSetText("[ERROR]\n Couldn't get Parcel Prim Owners", <1,0,0>, 1);
    }
    else
    {
        // Produce a copy of the list suitable for sorting by count, i.e. count then key 
        integer x;
        for ( ; x < gListLength; x += 2)
        {
            gListCountsAndOwners += llList2Integer(TempList, x+1);
            gListCountsAndOwners += osKey2Name(llList2Key(TempList, x));
        }
    }
}
default
{
    state_entry()
    {
        llSetText("Prim Owners\n", <1,1,1>, 1);
        gListCountsAndOwners=[];
        NameList=[];
    }
    touch_start(integer total_number)
    {
        llSetText("Scanning...\n", <1,1,0>, 1);
        gPrclID = [];
        gTotPrims = 0;
        // Start scan in the SW corner of the sim
        gX = 4.0;
        gY = 4.0;
        gNUM = 0;
        list TEMPLIST;
        TEMPLIST+="## Region: "+(string)llGetRegionName()+"\n";
        integer i;
        for (i = 0; i < 4096; i++)
        {
            list parcel = llGetParcelDetails(<gX,gY,100.0>,[PARCEL_DETAILS_ID,PARCEL_DETAILS_NAME]);
            key temp = llList2Key(parcel,0);                // The parcel's UUID
            string parcel_name = llList2String(parcel,1);   // The parcel's name
            if (parcel_name == "")
            {
                parcel_name = "(no name)";
            }
            if (!~llListFindList(gPrclID,[temp]))   // Have we scanned this parcel before?
            {
                ++gNUM;
                llSetText("Processing \n"+(string)parcel_name,<0,1,0>,1.0);
                CalcPrims(<gX,gY,100.0>);
                gPrclID += [temp];
            }
            if (gX < 512.0)     // Increment X but don't let X go outside the sim borders
            {
                gX +=8.0;
            }
            if (gX > 512.0)     // If it does, reset X and increment Y
            {
                gY += 8.0;
                gX = 4.0;
            }
            if (gY > 512.0)     // Don't let Y go outside the sim boders. If it does, wrap up the scan ....
            {
                //Tally List
                
                //Sort List
                gListCountsAndOwners = llListSort(gListCountsAndOwners, 2, FALSE);
                string NCname = llGetRegionName();
                osMakeNotecard(NCname,gListCountsAndOwners);
                //Create Notecard with data
                llOwnerSay("Total Parcels: "+(integer)gNUM);
                FinalOutput();
                gListCountsAndOwners=[];
                NameList=[];
                llSetText("Touch to start scan",<1.0,1.0,0.0>,1.0);
            }
        }
    }
}

 

Link to comment
Share on other sites

Meaning something like this, with llListReplaceList. Can't get inworld (let alone OS) to test it, but basically.. check for existing stride, get the land impact from it, add the new LI to it, then replace the old stride (start to start+1) with the new stride / updated sum. If the stride doesn't exist, just do the old logic.

CalcPrims(vector Loc)
{
    list TempList = llGetParcelPrimOwners(Loc);
    gListLength = llGetListLength(TempList);      
    if (!gListLength)
    {
        llSetText("[ERROR]\n Couldn't get Parcel Prim Owners", <1,0,0>, 1);
    }
    else
    {
        // Produce a copy of the list suitable for sorting by count, i.e. count then key 
        integer x;
        for ( ; x < gListLength; x += 2)
        {
            key owner = llList2Key(TempList, x);
            integer newLandImpact = llList2Integer(TempList, x+1);
            integer stride = llListFindList(gListCountsAndOwners, [owner]);

            if (stride != -1) // Found this owner before.
            {
                integer oldLandImpact = llList2Integer(gListCountsAndOwners, stride);
                list data = [
                    oldLandImpact + newLandImpact,
                    osKey2Name(llList2Key(TempList, x))
                ];
                gListCountsAndOwners = llListInsertList(gListCountsAndOwners, data, stride);
            }
            else
            {
                gListCountsAndOwners += llList2Integer(TempList, x+1);
                gListCountsAndOwners += osKey2Name(llList2Key(TempList, x));
            }
        }
    }
}

 

Edited by Wulfie Reanimator
  • Like 1
Link to comment
Share on other sites

need to do a lookup-update of gListCountsAndOwners in CalcPrims(). Off top of my head something like

for ( ; x < gListLength; x += 2)
{
    string owner = osKey2Name(llList2Key(TempList, x));
    integer count = llList2Integer(TempList, x + 1);
    integer index = llListFindList(gListCountsAndOwners, [owner])
    if (index % 2) // make sure the find is in column 2. owner name might be a number
    {   // prim owner is in list, so update
        --index;  // decrement to point to prim count
        count += llList2Integer(gListCountsAndOwners, index);
        gListCountsAndOwners = llListReplaceList(gListCountsAndOwners, [count], index, index);
    }
    else
    {   // prim_owner is not in list, so append
        gListCountsAndOwners += [count, owner];
    }

    ...

 

edit: what Wulfie said pretty much

 

edit more: is an error in what I posted. This line here: if (index % 2)

when not found index = -1.  -1 % 2 = -2.  if (-2) == TRUE

should be: if (index % 2 == 1)

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

1 hour ago, Ares Halostar said:

While this works in SL, I need it to work in Opensim as well, and llListSortStrided is not supported as yet.

Ohh, you need OpenSim compatibility. Okay then.

I was about to suggest using LSD, but I think OpenSim doesn't support that.

  • Thanks 1
Link to comment
Share on other sites

1 hour ago, primerib1 said:

Ohh, you need OpenSim compatibility. Okay then.

I was about to suggest using LSD, but I think OpenSim doesn't support that.

Does OpenSim support the JSON functions?  I'd use JSON instead of a list..

(but then again, I'd use LSD too if I needed to 'store' the data)

Link to comment
Share on other sites

Thanks for all the suggestions.  I finally got this thing to report in the format I needed.

Whilst I use the make notecard function to save the results, in LSL you will need to direct the output the way you need to.

If you wish to use it for a normal 256 sized region, you will have to adjust the Max scan float to 256 instead of 512.

Here is the script that works for me:

list    gListCountsAndOwners;       // Sorted list count+owner pairs
integer gOffset;
integer gIndex;
integer gListLength;
list gPrclID; 
integer gTotPrims;
integer gNUM; 
float gX;
float gY;  
CalcPrims(vector Loc)
{
    list TempList = llGetParcelPrimOwners(Loc);
    gListLength = llGetListLength(TempList);      
    if (!gListLength)
    {
        llSetText("[ERROR]\n Couldn't get Parcel Prim Owners", <1,0,0>, 1);
    }
    else
    {
        // Produce a copy of the list suitable for sorting by count, i.e. count then key 
        integer x;
        for ( ; x < gListLength; x += 2)
        {
            string owner = osKey2Name(llList2Key(TempList, x));
            integer count = llList2Integer(TempList, x + 1);
            integer index = llListFindList(gListCountsAndOwners, [owner]);
            if (index % 2 == 1) // make sure the find is in column 2. owner name might be a number
            {   // prim owner is in list, so update
                --index;  // decrement to point to prim count
                count += llList2Integer(gListCountsAndOwners, index);
                gListCountsAndOwners = llListReplaceList(gListCountsAndOwners, [count], index, index);
            }
            else
            {   // prim_owner is not in list, so append
                gListCountsAndOwners += [count, owner];
            }
        }
        //llOwnerSay(llList2CSV(gListCountsAndOwners));
    }
}
default
{
    state_entry()
    {
        llSetText("Show Prim Owners\nTouch to scan region", <1,1,1>, 1);
        gListCountsAndOwners=[];
    }
    touch_start(integer total_number)
    {
        llSetText("Scanning...\n", <1,1,0>, 1);
        gPrclID = [];
        gTotPrims = 0;
        // Start scan in the SW corner of the sim
        gX = 4.0;
        gY = 4.0;
        gNUM = 0;
        integer i;
        for (i = 0; i < 4096; i++)
        {
            list parcel = llGetParcelDetails(<gX,gY,100.0>,[PARCEL_DETAILS_ID,PARCEL_DETAILS_NAME]);
            key temp = llList2Key(parcel,0);                // The parcel's UUID
            string parcel_name = llList2String(parcel,1);   // The parcel's name
            if (parcel_name == "")
            {
                parcel_name = "(no name)";
            }
            if (!~llListFindList(gPrclID,[temp]))   // Have we scanned this parcel before?
            {
                ++gNUM;
                llSetText("Processing Parcel:\n"+(string)parcel_name,<0,1,0>,1.0);
                CalcPrims(<gX,gY,100.0>);
                gPrclID += [temp];
            }
            if (gX < 512.0)     // Increment X but don't let X go outside the sim borders
            {
                gX +=8.0;
            }
            if (gX > 512.0) // If it does, reset X and increment Y
            {
                gY += 8.0;
                gX = 4.0;
            }
            if (gY > 512.0) // Don't let Y go outside the sim boders. If it does, wrap up the scan ....
            {
                string NCname = llGetRegionName();
                string ReportName = "## Region: "+(string)NCname+" - Total Parcels: "+(integer)gNUM+"\n";
                gListCountsAndOwners = llListSort(gListCountsAndOwners, 2, FALSE);
                integer Length = llGetListLength(gListCountsAndOwners);
                integer z;
                integer Inc;
                string Output;
                for ( ; z < Length; z++)
                {
                    Inc+=1;
                    Output+=(string)llList2String(gListCountsAndOwners,z);
                    Output+=" ";
                    if(Inc==2) 
                    {
                        Output+="\n";
                        Inc=0;
                    }
                }
                osMakeNotecard(NCname, ReportName+"\n"+Output);
                llOwnerSay("Total Parcels: "+(integer)gNUM+"\nReport Notecard "+(string)NCname+" saved to prim inventory");
                gListCountsAndOwners=[];
                llSetText("Show Prim Owners\nTouch to scan region", <1,1,1>, 1);
            }
        }
    }
}

 

Thanks again for all the help.  

 

Edited by Ares Halostar
Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 204 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...