Sort List by more than 1 field?
BlitzMax Forums/BlitzMax Programming/Sort List by more than 1 field?
| ||
Hi all, I need to be able to sort a list by more than 1 criteria. I am putting together an app that shows the order in which golfers play their shots. The order rules are different depending on the situation. For tee shots the order is by score, lowest to highest. For all other shots the order is by distance, highest to lowest. No problem here. The problem is that for tee shots where the scores are identical, I need to sort by score and then if 2 or more players have the same score, sort by name. Here is what I have: Type player Global what_order:Int Field playernum:Int Field name:String Field distance:Float Field distrounded:Int Field strokes:Int Field inhole:Int Field donetee:Int Method Compare:Int(Other:Object) If other=Null Return 0 If what_order=0 ' this means (for use) 'order bades on VALUE field If distance = player(other).distance Return 0 If distance < player(Other).distance Then Return 1 Else Return -1 Else 'order based on strokes field If strokes = player(other).strokes Return 0 If strokes > player(other).strokes Then Return 1 Else Return -1 End If End Method End Type Does anyone have any tips for this? |
| ||
Override the compare method of the classes bein sorted to take into account as much fields as you wish. A simple example to see how sorting works with lists (it is the same with arrays) Strict Type TMyClass Field One:String Field Two:String 'This should return 1 if the withobject is smaller, 0 if both are the same and -1 if it is bigger: Method Compare:Int(withObject:Object) 'If the class is compared with a different one: If TMyClass(withObject) = Null Then Return Super.Compare(withObject) 'If the class is compared with a 2 fields sortable class: Local Comparer:TMyClass = TMyClass(withObject) If Comparer.One < One Then Return 1 If Comparer.One > One Then Return - 1 If Comparer.Two > Two Then Return - 1 If Comparer.Two < Two Then Return 1 Return 0 End Method 'Just a simple debug ToString function: Method ToString:String() Return ("One = " + One + ", Two = " + Two) End Method End Type 'We fill a list with random instances of the class, with random values on the fields one and two Local List:TList = New TList For Local i:Int = 0 To 40 Local Class:TMyClass = New TMyClass Class.One = Chr(Rand(65, 67)) Class.two = Chr(Rand(65, 80)) + Chr(Rand(65, 80)) + Chr(Rand(65, 80)) + Chr(Rand(65, 80)) List.AddLast(Class) Next 'We show the contents: Print "Unsorted:" For Local Class:TMyClass = EachIn List Print Class.Tostring() Next Print "Sorted:" List.Sort() For Local Class:TMyClass = EachIn List Print Class.Tostring() Next |
| ||
Thanks ziggy, checking it out now. |
| ||
As an addition do not override the Compare method. If you do you're just opening yourself up to a whole world of pain as Sort is not the only function that uses the Compare method. Declare a custom compare function to go along with the SortList function.SortList list,True,CustomCompare Function CustomCompare:Int( o1:Object, o2:Object ) 'Compare code here End Function |
| ||
As an addition do not override the Compare method. If you do you're just opening yourself up to a whole world of pain as Sort is not the only function that uses the Compare method. I've never had problems with overloading the compare method when needed. So all in all, I'm very curious to know wich methods could give problems with this, just to be aware.Also, how can you sort then an array? |
| ||
The Remove methods and functions use the Compare method. They will remove the first entry that fits the criteria, which if you have overridden the Compare method might not be the object you intended. If you are not using lists and only using arrays then overriding Compare should be ok. Just be warned. |
| ||
I thought that was solved. Anyway, thanks a lot, I wasn't aware of this. [EDIT] I've been looking at the source code of linkedlists and, as long as you're using unique fields for sorting (you don't keep duplicates on the lists) there are not any potential issues overriding the compare method. Otherwise, the method will remove (or find) the first instance that compareas as 'equal'. |
| ||
By "using unique fields" do you mean that I might run into a problem unless I create a custom compare function as Oddbal suggests? Since the "strokes" field in my type are often have the same value. |
| ||
You can replace "Return 0" with "Return super.compare(Other)" to avoid that problem. |
| ||
Thanks for the tips guys, it is working great now. |
| ||
@Tommo: Thanks! That's the easiest way to prevent any problem with the overridden compare method. How I wish this was documented... |