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