Question on Lists

BlitzMax Forums/BlitzMax Beginners Area/Question on Lists

Ranoka(Posted 2011) [#1]
My question is, can a list be iterated/looped through backwards?

For Local foo:BaType = EachIn fooList
    InterestingFunction(foo)
Next


The only solution I can think of is to reverse the list, iterate through it, and then reverse it again. Which doesn't seem very efficient.

Or go back through, and reverse all my logic to allow for only iterating through a list forwards.

Any help/tips appreciated!


GfK(Posted 2011) [#2]
You can use TLinks to start at the end and work back to the beginning.

[edit] Quick and dirty example:
Strict

Local list:TList = New TList

For Local n:Int = 1 To 10
	list.addlast(String(n))
Next

Local link:TLink

link = list.lastlink()
Repeat
	Print String(link._value)
	link = link.prevlink()
Until link = Null


Last edited 2011


ima747(Posted 2011) [#3]
quick and dirty: reverse the list.

very efficient: do what GFK says

wasteful but possibly easy to read later: treat the list like an array by accessing the elements by their location with ValueAtIndex().

going one wasteful step further, convert the list to an array and then access locations...

long story short, there's no built in way, GFK's post would be the most efficient, but the "native" approach (i.e. not digging into the links themselves) would probably be to reverse the list and go through that. I wouldn't expect that to be too prohibitively slow, though it will obviously depend on the size of your list and how critical speed really is for you...

working with copies of lists can be handy by the by: e.g. if you need to remove things from a list as you go through it. loop through a copy of the list and when you find something that needs removing, pop it out of the master list. Since you're iterating a different list you can make changes to the original... this can also be used sometimes in multithreaded applications to not have to lock a list for the entire time spent looping through it, so long as you keep in mind that the copy is only a snap shot of the list from when the iteration started...

I seem to have rambled, hope GFKs answer was the one you were looking for :0)


Ranoka(Posted 2011) [#4]
Thanks for the explanation ima747, I do appreciate it.
I will probably use GfK's approach for what I'm doing. So thanks for that clear example GfK!

I'm starting off with quite a basic retro style game from the Spectrum, so speed isn't a great issue, and I currently have 7 lists each with 30 links, so I probably could do any of these and not notice a difference.

I have done some Flash and am used to using their slow but flexible arrays (which are nothing like normal/real arrays really).
I haven't really seen much use of linked lists in AS3. I've heard people doing C++ talk about them. I thought I would get some practice in by using them on my simple project.

Cheers again.


Czar Flavius(Posted 2011) [#5]
You should use a While loop rather than a Repeat loop?? What happens if the list is empty? (I don't know, does the link come out Null) Also use the method Value() rather than accessing the field _value directly. Nicer that way.

You can also use list.Reverse() to reverse that list and list2 = list.Reversed() to make a second list of the same objects but reversed. They are slow operations. But if the list won't be modified anymore and you need to go backwards often, you could use them.

Last edited 2011

Last edited 2011


Ranoka(Posted 2011) [#6]
I'm not sure a 2nd copy of the list would be that helpful, because I'm changing the order of the links every update: removing the back one and putting it on the front.

If I wasn't planning on changing the order of the contained objects so much I would probably just use an array.

So wouldn't the 2nd list be in a different order than a reversed order of the first after I've changed some links?

Last edited 2011


GfK(Posted 2011) [#7]
So wouldn't the 2nd list be in a different order than a reversed order of the first after I've changed some links?
Yes, it would. Its daft to maintain two separate lists when you can do the job [much easier] with one.
You should use a While loop rather than a Repeat loop?? What happens if the list is empty?
Probably, unless you know for sure the list isn't going to be empty at that point. Otherwise you'll get an attempt to reference null object error with my code as is.

Last edited 2011


Perturbatio(Posted 2011) [#8]
One possible longer term solution would be to extend TList and TListEnumerator

You could create a property on the list that determines the iteration order and then your new TListEnumerator would check this and act accordingly.

Only useful if you're likely to do this a lot.


Ranoka(Posted 2011) [#9]
To be honest, if I knew more about lists before I began and knew you could only iterate through them forwards, then I would have done my logic with that in mind. At this point I think I'll work around that rather than reversing the logic (maybe I'll refactor it later).

My lists always have something in them currently, but I think I'll need to animate them being emptied, so I'll keep the null exception in mind. Thanks for the heads up!


Zeke(Posted 2011) [#10]
http://www.blitzmax.com/Community/posts.php?topic=82916#935611


Czar Flavius(Posted 2011) [#11]
removing the back one and putting it on the front.
Why not remove the front one and put it on back?


Ranoka(Posted 2011) [#12]
Because that's the reverse of what I need, and would cause the game element to go backwards.

Also, I need to start with the back of the List so that it's drawn behind what's in front.

I could reverse both of these things, but then the data and code is harder to understand.


Czar Flavius(Posted 2011) [#13]
Is it a drawing list? Make a compare function to sort them by y coordinate and descending sort the list each frame. I do it in my big game and there is no performance problem with hundreds of units.


dmaz(Posted 2011) [#14]
http://www.blitzmax.com/codearcs/codearcs.php?code=1807
it allows
local list:TListF = new TListF
for blah:yourtype = eachin list.From(start:TLink,howMany:int=-1)
or
for blah:yourtype = eachin list.ReverseFrom(start:TLink,howMany:int=-1)
or
for blah:TLink = eachin list.LinksFrom(start:TLink,howMany:int=-1)

if howMany is -1 then it will continue to the end or the begining as in the case of ReverseFrom.