Finding an object in a list?
BlitzMax Forums/BlitzMax Beginners Area/Finding an object in a list?
| ||
How can I check for the existance of an object in a list without having to iterate through the list? I'm after a ListFindObject() type of function. ListFindLink() is closest but how do I get the 'fruit' type object? Quick example: Global mylist:TList=CreateList() Type fruit Field name$ Method New() ListAddLast mylist,Self End Method End Type Local f:fruit f=New fruit ; f.name$="apple" f=New fruit ; f.name$="banana" f=New fruit ; f.name$="pear" f=New fruit ; f.name$="orange" f=New fruit ; f.name$="peach" f=ListFindObject("pear") ???????????????? If f ListRemove mylist,f |
| ||
Its not very effective but you could do it this way.Global mylist:TList=CreateList() Type fruit Field name$ Function FindObject:fruit(_Name:String) For t:fruit = EachIn mylist If t.name = _name Then Return t Exit EndIf Next Return End Function Method New() ListAddLast mylist,Self End Method End Type Local f:fruit f=New fruit ; f.name$="apple" f=New fruit ; f.name$="banana" f=New fruit ; f.name$="pear" f=New fruit ; f.name$="orange" f=New fruit ; f.name$="peach" f = Null ' Important f=fruit.FindObject("pear") If f ListRemove mylist,f For f = EachIn mylist Print f.name Next |
| ||
I have tried playing with TLink() but always get a Null object ..Global mylist:TList=CreateList() Type fruit Field name$ End Type Local f:fruit f=New fruit ; f.name$="apple" ; ListAddLast mylist,f f=New fruit ; f.name$="banana" ; ListAddLast mylist,f f=New fruit ; f.name$="pear" ; ListAddLast mylist,f f=New fruit ; f.name$="orange" ; ListAddLast mylist,f f=New fruit ; f.name$="peach" ; ListAddLast mylist,f 'DebugStop f=FindFruit("pear") If f Print f.name$ Else Print "not found" End Function FindFruit:fruit(value:Object) Local t:TLink=ListFindLink(mylist,value) If t Return fruit(t.value()) End Function |
| ||
Unfortunately, you probably can't. That's just a limitation of linked lists. I plan on making a hash-map module at some point in the near future, just have to get around to it. |
| ||
Another way to find an object is to give the object a special id and then use this.Global mylist:TList=CreateList() Type fruit Field name$ Field id = mylist.Count() End Type Local f:fruit f=New fruit ; f.name$="apple" ; ListAddLast mylist,f f=New fruit ; f.name$="banana" ; ListAddLast mylist,f f=New fruit ; f.name$="pear" ; ListAddLast mylist,f f=New fruit ; f.name$="orange" ; ListAddLast mylist,f f=New fruit ; f.name$="peach" ; ListAddLast mylist,f f = fruit(mylist.Valueatindex(2)) If f Print f.name$ Else Print "not found" End |
| ||
Thanks you two. I've been getting confused by object and value it seems. Looks like I do need to iterate through the list .. Global mylist:TList=CreateList() Type fruit Field name$ End Type Global flag Local f:fruit f=New fruit ; f.name$="apple" ; ListAddLast mylist,f f=New fruit ; f.name$="banana" ; ListAddLast mylist,f f=New fruit ; f.name$="pear" ; ListAddLast mylist,f f=New fruit ; f.name$="orange" ; ListAddLast mylist,f f=New fruit ; f.name$="peach" ; ListAddLast mylist,f 'DebugStop f=FindFruit("pear") If f ListRemove mylist,f For f=EachIn mylist Print f.name$ Next FlushMem End Function FindFruit:fruit(name$) For Local fr:fruit=EachIn mylist If fr.name$=name$ Return fr Next Return Null End Function |
| ||
You can always give an object an unique handle. See my bottom example. This does not replace the need to find objects by field but in many cases you can save both time and code by having direct links to objects;types you use often. When you used MyList.FindLink("Pear") you gave the method an String and it cannot convert that to an object. In other words that string was not found in the list. In the example below I add strings to the list. You could do the same with 'real' objects also. Depends on what you really want to do in the end. Hope those examples shed some light on Lists =) |
| ||
Here is my version of a hashtable. I'm sure someone can make a better one, but it has worked so far for me... Use it like this... Local MyTable:HashTable = HashTable.Create(500) MyTable.Add("Apple","I'm an apple!") MyTable.Add("Pear","I'm a pear!") MyTable.Add("Orange","I'm an orange!") Print String(MyTable.GetValue("Pear")) If MyTable.ContainsKey("Peach")=False then Print "No peach in the table" Each key must be unique and if you try to add one that already exist, it will just skip adding it. |
| ||
Why not just give your object a compare method? FindLink will use it.Type TMe Field name:String Function Create:TMe(n:String) Local x:TMe=New TMe x.name=n Return x EndFunction Method ToString:String() Return name EndMethod Method Compare:Int(o:Object) other:TMe=TMe(o) If other If name=other.name Return 0 ElseIf name<other.name Return -1 ElseIf name>other.name Return 1 EndIf EndIf EndMethod EndType Local l:TList l=New TList l.AddLast(TMe.Create("AB")) l.AddLast(TMe.Create("BB")) l.AddLast(TMe.Create("BC")) link:TLink=l.FindLink(TMe.Create("BB")) DebugLog link.value().tostring() |
| ||
This opens up a whole new world. Its just a matter of knowing how to tackle them. Waves first example will do for me since I only need to have a list of lines read from a file. Thanks everyone. Good stuff indeed. |