Jump to content

Sorting list by 2 criteria?


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

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

Recommended Posts

I'm trying to figure out how to sort a list of scores, and names, but maintain the player's place on the scoreboard if someone ties with them. for example, player 1 has a score of 15, then player 3 gets a score of 15, player 1 should stay in 1st place, and player 3 should move up to second place. following?

i used the following script, but it didn't maintain the places as i expected.

list scores = [15,"player 1", 12, "player 2", 19, "player 3", 15, "player 4", 12, "player 5"];
default
{
    state_entry()
    {
        scores = llListSort(scores, 2, FALSE);
        llOwnerSay(llList2CSV(scores));
    }
}
//Returns: [19:42] 19, player 3, 15, player 4, 15, player 1, 12, player 5, 12, player 2

So i thought what about adding another "column" of the unix time when that player last scored. but i don't know how i'd go about sorting the list both by the scores descending, and the unix time ascending.

someone suggested crunching the score, unix time and name together in a string, sorting, then extracting them again, but that didn't work either, and sorts it the same way since the lower unix time added to the same score is also going to sort in descending order

list scores = [15,2001,"player 1", 12,2004, "player 2", 19,2004, "player 3", 15,2002, "player 4", 12,2005, "player 5"];
default
{
    state_entry()
    {
        list temp = [];
        integer i;
        integer len = llGetListLength(scores);
        for(i = 0; i < len; i += 3)
        {
            temp += llDumpList2String(llList2List(scores, i, i+2),"");
        }
        llOwnerSay(llList2CSV(temp));
        temp = llListSort(temp,1,FALSE);
        llOwnerSay(llList2CSV(temp));
        scores = llListSort(scores, 3, FALSE);
        llOwnerSay(llList2CSV(scores));
    }
}
//returns: [20:32] 152001player 1, 122004player 2, 192004player 3, 152002player 4, 122005player 5
[20:32] 192004player 3, 152002player 4, 152001player 1, 122005player 5, 122004player 2
[20:32] 19, 2004, player 3, 15, 2002, player 4, 15, 2001, player 1, 12, 2005, player 5, 12, 2004, player 2

 

Link to comment
Share on other sites

Generally speaking, if you want to sort by multiple categories, first sort by one category before the other.

This is a pretty common solution in many places, and it's basically an "accidental coincidence" that it works this way, because of how sorting functions typically work. It's a bit hard to explain without illustrating it.

The biggest problem is that you can't sort strides by a specific column, the strides are sorted by the first element only. So you would have to rebuild the list in a different format before sorting it the second time. For that reason, it might be simple to combine the score and timestamp as you suggested. I'd recommend a string format of "score-unixtime" as in "15-2004" This way, if two players have the same score, you would sort "15-2004" and "15-4008" next to each other in ascending/descending order.

 

Edited by Wulfie Reanimator
Link to comment
Share on other sites

think i figured it out, but there's gotta be a more efficient way of doing it 😕 

it's getting the time when the loop is about to start, then replaces the unix time in the temp list with the time since that player's score was last updated. formatted by lumping it together as "score-timesince-name" then sorting, it sorts how i wanted it to.

then it parses each of those lumped strings, then converts the timesince back to the original unix time, and reconstructs the score list

list scores = [15,2001,"player 1", 12,2004, "player 2", 19,2004, "player 3", 15,2002, "player 4", 12,2005, "player 5"];
default
{
    state_entry()
    {
        list temp = [];
        integer i;
        integer len = llGetListLength(scores);
        integer now = 2006;
        for(i = 0; i < len; i += 3)
        {
            integer score = llList2Integer(scores,i);
            integer since = now - llList2Integer(scores, i+1);
            string name = llList2String(scores,i+2);
            temp += llDumpList2String([score,since,name],"-");
        }
        llOwnerSay(llList2CSV(temp));
        temp = llListSort(temp,1,FALSE);
        llOwnerSay(llList2CSV(temp));
        len = llGetListLength(temp);
        scores = [];
        for(i = 0;i < len; i++)
        {
            list temp2 = llParseString2List(llList2String(temp,i),["-"],[]);
            integer score = llList2Integer(temp2,0);
            integer time = now - llList2Integer(temp2,1);
            string name = llList2String(temp2,2);
            scores += [score,time,name];
        }
        llOwnerSay(llList2CSV(scores));
    }
}
//returns: [21:35] 15-5-player 1, 12-2-player 2, 19-2-player 3, 15-4-player 4, 12-1-player 5
[21:35] 19-2-player 3, 15-5-player 1, 15-4-player 4, 12-2-player 2, 12-1-player 5
[21:35] 19, 2004, 2006, 15, 2001, 2006, 15, 2002, 2006, 12, 2004, 2006, 12, 2005, 2006
[21:35] 15-5-player 1, 12-2-player 2, 19-2-player 3, 15-4-player 4, 12-1-player 5
[21:35] 19-2-player 3, 15-5-player 1, 15-4-player 4, 12-2-player 2, 12-1-player 5
[21:35] 19, 2004, player 3, 15, 2001, player 1, 15, 2002, player 4, 12, 2004, player 2, 12, 2005, player 5

 

Link to comment
Share on other sites

3 hours ago, Ruthven Ravenhurst said:

I'm trying to figure out how to sort a list of scores, and names, but maintain the player's place on the scoreboard if someone ties with them. for example, player 1 has a score of 15, then player 3 gets a score of 15, player 1 should stay in 1st place, and player 3 should move up to second place. following?

 

a way is have a unique record number for each new entry added to the list

example:

integer record_uid = 0xFFFFFFFF; // unique record ident

list players;

addnew_player(key player, integer score)
{    
    // decrement record_uid. when this rolls over from - to + then the current list needs to be reset
    --record_uid;
    if (record_uid == 0xFFFFFFFF)
      reset_record_uid();

    // append new player. record format:
    // [score, record_uid, player]
    players += [score, record_uid, player];
    
    // sort new player into list, in descending order
    // sort by Score - high to low
    // sort by record_id - which is unique to every entry in the list. - high to low
    // sort by player - high to low
    players = llListSort(players, 3, FALSE);
}

update_player(key player, integer score)
{
    integer i = llListFindList(players, [player]);
    if (~i)
        players = llListSort(llListReplaceList(players, [score], i-2, i-2), 3, FALSE);
}

reset_record_uid()
{
   record_uid = 0xFFFFFFFF;
   integer n = llGetListLength(players);
   integer i;
   for (i = 1; i < n; i += 3)
       players = llListReplaceList(players, [--record_uid], i, i);
}

 

 

 

 

Edited by Mollymews
code typeo
Link to comment
Share on other sites

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