# Sorting list by 2 criteria?

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```

##### 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
##### 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```

##### 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;

{
// 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