TList question - Moving through list

BlitzMax Forums/BlitzMax Beginners Area/TList question - Moving through list

Sin of Nature(Posted 2007) [#1]
Hi,
Always get frustrated with TList's. There is a command

MyTList.First

This moves the point to the first entry. There is also the command

MyTList.Last

But if I want to move forward 1 entry though the list, how do I do it without using a for... each loop. In BlitzPlus, sure there was a command like MyTList.Next but cant seem to find the same under BlitzMAX

Sin


Gabriel(Posted 2007) [#2]
http://www.blitzbasic.com/Community/posts.php?topic=50285


Sin of Nature(Posted 2007) [#3]
Thanks, but to be honest that seems quite extreme to do a simple task. Cant believe they did not add that command to BlitzMax.

All I want to do is change a value at a particular entry (String TList). The MyTList.ValueAtIndex(Entry) only displays it, but I want to actually change that value at that point.

I cant use for...each loop (wont go into why). Anyone able to whip up a quick example?

Sin


fredborg(Posted 2007) [#4]
Local txt:Object[] = ListToArray(list)
txt[index] = "hello"
list = ListFromArray(txt)



Gabriel(Posted 2007) [#5]
Cant believe they did not add that command to BlitzMax.

It isn't possible to do it exactly the same way. Lists do much more than they did in B3D/B+.

The MyTList.ValueAtIndex(Entry) only displays it, but I want to actually change that value and that point.

I have no idea what you mean. Either you have the type instance you want or you don't. There's no such thing as read-only types.

Type Thing
	Field X:Int
End Type

Global List:TList


Global AThing:Thing=New Thing
AThing.X=5
List=New TList
List.AddLast(AThing)

Global BThing:Thing=Thing(List.ValueAtIndex(0))
BThing.X=10

Print AThing.X



simonh(Posted 2007) [#6]
	Method Before:Object()
	
		Local link:TLink=List.FindLink(Self).PrevLink:TLink()
		If link<>Null
			Return link.Value:Object()
		Else
			Return Null
		EndIf
	
	End Method

	Method After:Object()
	
		Local link:TLink=List.FindLink(Self).NextLink:TLink()
		If link<>Null
			Return link.Value:Object()
		Else
			Return Null
		EndIf
	
	End Method



Sin of Nature(Posted 2007) [#7]
Bare with me, my head hurts with this stuff. :-D What I ment is that you cant do:

MyTList.ValueAtIndex(Entry) = "Hello"


Thanks, but what I'm having trouble with is that fact I have a Tlist of Strings. There are no Types involved

Global MyTList:TList = CreateList()

For x:Int = 1 to 10
   ListAddLast MyTList,String(x)
Next


OK, now I want to change the value at position 4 to say "bob" without using a for...each loop.

I have not defined any types (as the added entries are just strings) and thats what my head cant get round.

I tried the ToArray and FromArray command but it wont update my list when using the FromArray command???

Sin


Sin of Nature(Posted 2007) [#8]
OK, I've never used the TLink command before. If I didnt want to create a method and access it directly, how would I do it?

This does not work, as I dont know what to pass as the FindLink() method.

Global MyTList:TList = CreateList()

For x:Int = 1 To 10
   ListAddLast MyTList,String(x)
Next



For Local I:String = EachIn MyTList
	Print(I)
Next	


Local Test1:String

Test1 = String(MyTList.ValueAtIndex(4))
Print "Test1 = "+Test1


Local link:TLink=MyTList.FindLink(MyTList.ValueAtIndex(4))
Test2 = String(link.value)
Print "Test2 = "+Test2

WaitKey()



Perturbatio(Posted 2007) [#9]
http://www.blitzbasic.com/codearcs/codearcs.php?code=1584


ImaginaryHuman(Posted 2007) [#10]
Looking at the TList type I don't know why you don't just look at the pred/succ fields which point directly to the previous and next objects in the list ie mylist._succ


Curtastic(Posted 2007) [#11]
I can't believe ListNext isn't a command. So many people keep having this same problem. It really should be built in even if it has to search the list. Look at ListRemove, its already known to be slow because it searches the whole list. Yet we use it anyways because its simple.


Sin of Nature(Posted 2007) [#12]
**AngelDaniel**
I dont understand. How do I use this MyList._succ you speak of? Comes up with errors in the example above.

Print MyTList._succ 

Can you show me what you mean?

*** Curtastic ***
I agree 100%. I got used to BlitzPlus and then they changed it in BlitzMax. Just having a few issues adjusting.

Has anyone got any tutorials on TLists and more importantly TLinks? I'm sorry, but the BlitzMax docs simply dont cut it for explanations the use of commands.


Sin


ImaginaryHuman(Posted 2007) [#13]
The TList object is the `header` of the linked list, and it contains a pointer to the first link in the list. Each link is, if I remember right, a `TLink` object, containing a pointer to the previous TLink and a pointer to the next TLink and a pointer to the object that you stored in the link. So you need to work from the link, not the list itself. Get the link of the object that you are interested in, which returns a TLink object, and then go myTLink._succ to get the next link or myTLink._pred to get the previous link. Note that these are internal variables so BRL can potentially change them in future. All you're doing is directly accessing the previous or next link from within a given link, which is what you want. I thought there was a method that does this?

Here's what the TLink object looks like (from the linkedlist.mod module):

Type TLink

	Field _value:Object
	Field _succ:TLink,_pred:TLink
	
	Rem
	bbdoc: Returns the Object associated with this Link.
	End Rem
	Method Value:Object()
		Return _value
	End Method

	Rem
	bbdoc: Returns the next link in the List.
	End Rem
	Method NextLink:TLink()
		If _succ._value<>_succ Return _succ
	End Method

	Rem
	bbdoc: Returns the previous link in the List.
	End Rem
	Method PrevLink:TLink()
		If _pred._value<>_pred Return _pred
	End Method

	Rem
	bbdoc: Removes the link from the List.
	End Rem
	Method Remove()
		_value=Null
		_succ._pred=_pred
		_pred._succ=_succ
	End Method

End Type

So either you can find the link using myLink:TLink=myTList.FindLink(), and then do nextLink=myLink._succ (or myLink._pred for previous), or you can use the method myTLink.NextLink() and myTLink.PrevLink()

Also look at this code from the TList object: It get the _head field from the TList object, which is the pointer to the first TLink in the list, and then goes through all of them to find the link that you want.
	Method FindLink:TLink( value:Object )
		Local link:TLink=_head._succ
		While link<>_head
			If link._value.Compare( value )=0 Return link
			link=link._succ
		Wend
	End Method

I prefer to either write my own more efficient linked list or at least look at _pred and _succ rather than go via a timewasting `get` method.


EOF(Posted 2007) [#14]
I wrote this example which uses TLink to move up/down through a list. Guidance is in the code:





And a simplified / clearer example to follow:



Sin of Nature(Posted 2007) [#15]
Thanks! That is much clearer now.

TLink is pretty much the same as link lists in C++/Pascal (showing my age). I think I can work round my problem with those examples :D

Cheers

Sin


Sin of Nature(Posted 2007) [#16]
Jim Brown:
Hi, 1 quick question. Your example code does everything except change a current an existing value to something else.

I'm assuming this is not possible, so how would I do it?

link.value() = "Bob"


Sin


SculptureOfSoul(Posted 2007) [#17]
Sin, this should work

link._value = "Bob"


Note that link._value is of type object, so you can't assign it a simple number or float or anything. Strings are objects in Blitzmax, hence why the above will work.


EOF(Posted 2007) [#18]
As SculptureSoul says, use link._value = "blah"

Revised both of my examples from above:







GfK(Posted 2007) [#19]
I'd do it this way. Personal preference I suppose, I just find it simpler. This isn't checking for errors but all you'd need to do is check for null returns before trying to change Type contents:
Global stringList:TList = New TList
Local s:tString

'put some random chars in list
For N = 1 To 10
	s = New tString
	s.text = Chr$(Rand(65,97))
	stringList.addLast s
Next

'change value of item 4
s = tString(stringList.valueAtIndex(4))
s.text = "Replaced this item!"

'find next link and change value
getNext(s).text = "Replaced the next one too!"


'output
For s = EachIn stringList
	DebugLog s.text
Next

'function to get next object in list
Function getNext:tString(nLink:tString)
	nLink = tString(stringList.FindLink(nLink).NextLink().Value())
	Return nLink
End Function

'declaration
Type tString
	Field text:String
End Type



tonyg(Posted 2007) [#20]
The use of next,prev etc is fine for both string and type objects but how does FindLink work with type objects?
Here's Jim's code changed to use a TTEST

As we no longer have 'known' or unique link names aren't we stuck to looping through the list checking each mytest.name until we find 'Shed' again.
Is this where you'd use a tmap or store a link in a type field (although won't we need to find the instance before we can use it?)?


SculptureOfSoul(Posted 2007) [#21]
Tony, that code won't work as FindLink is comparing the object provided as an argument against the object stored in each link. Since you don't have "Shed" stored anywhere, but instead have a TTEST in there, it won't find anything.

If you want to associate a string name (or key) to a value, you're better off using TMap's or my THashtable (http://www.blitzmax.com/codearcs/codearcs.php?code=1907)

For instance, with the THashtable, you could go
global Hash:THashtable = THashtable.Constructor(50) 'make a 50 element hash tale

global test:ttest = new ttest
test.name = "Test name"

Hash.InsertEntry( test.name, test )
'this stores the object test with the key "Test name". Of course, any string or numeric key could be used.



And then, when you want to retrieve an entry, all you need to know is it's key value

global ttest_return:ttest

'the basic call to get an object back is Hash.GetEntry( "key value here"), 
'but we must cast the result back since the hash stores & returns objects, so the final call ends up being

ttest_return = ttest(Hash.GetEntry( "Test name" ))


Note that key names are case sensitive.


tonyg(Posted 2007) [#22]
Thanks SculptureOfSoul but isn't that what I said ;-)?


SculptureOfSoul(Posted 2007) [#23]
Well, technically you asked it, but yeah, I suppose so. ;)


Sin of Nature(Posted 2007) [#24]
Thanks all. Great info.

Sin