HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Looping through a group

10-03-2009, 06:13 PM#1
Storyyeller
What is the best way to loop through a group?

This is what I came up with, but it seems kind of ugly. Is there any better way?
Collapse JASS:
globals
    group CampList = CreateGroup()
endglobals

function DoSpawnLogic takes nothing returns nothing
    local group LocalCampListCopy = CreateGroup()
    local unit LoopUnit
    
    loop
        set LoopUnit=FirstOfGroup(CampList)
        exitwhen LoopUnit==null
        
        //Do stuff to LoopUnit
        
        call GroupRemoveUnit(CampList,LoopUnit)
        call GroupAddUnit(LocalCampListCopy, LoopUnit)
    endloop
    
    call DestroyGroup(CampList)
    set CampList = LocalCampListCopy
    set LoopUnit = null
endfunction
10-03-2009, 06:40 PM#2
Captain Griffen
ForGroup.
10-03-2009, 08:37 PM#3
Cheezeman
Collapse JASS:
function callback takes nothing returns nothing
    local unit LoopUnit = GetEnumUni()
    //Do stuff to LoopUnit
endfunction

function Actions takes nothing returns nothing
    call ForGroup( CampList, function callback )
endfunction
10-03-2009, 08:55 PM#4
Storyyeller
Thanks, I have it working now
10-04-2009, 11:44 AM#5
Anachron
this is how i do it:

Collapse JASS:
function forGroup takes group g returns nothing
    local unit u = null
    local boolean e = false
   
    loop
        exitwhen e
        
        set u = FirstOfGroup(g)
        if u != null then
            call GroupRemoveUnit(g, u)
            call doStuff
        else
            set u = null
            set e = true
        endif
    endloop

endfunction
10-04-2009, 02:14 PM#6
Captain Griffen
Please, if you're going to suggest FirstOfGroup loops, tell them about the problems you can get with that. And that's a horrible implementation anyway. ForGroup is far superior in speed, and, in many cases, actually works properly where FoG loops don't.
10-04-2009, 10:31 PM#7
Anitarf
Quote:
Originally Posted by Anachron
this is how i do it:

Collapse JASS:
function forGroup takes group g returns nothing
    local unit u = null
    local boolean e = false
   
    loop
        exitwhen e
        
        set u = FirstOfGroup(g)
        if u != null then
            call GroupRemoveUnit(g, u)
            call doStuff
        else
            set u = null
            set e = true
        endif
    endloop

endfunction
Why do you need that extra boolean e? An exitwhen true statement under the else actions would suffice.
10-04-2009, 11:30 PM#8
ToukoAozaki
Quote:
Originally Posted by Anitarf
Why do you need that extra boolean e? An exitwhen true statement under the else actions would suffice.

if statement is also unnecessary. Whole point of FirstOfGroup loop is meaningless though...
10-05-2009, 02:19 AM#9
Rising_Dusk
If you must use FirstOfGroup, do this:
Collapse JASS:
loop
    set SomeUnit = FirstOfGroup(MyGroup)
    exitwhen SomeUnit == null
    //Do stuff
    call GroupRemoveUnit(MyGroup, SomeUnit)
endloop
10-05-2009, 02:53 AM#10
Ignitedstar
Quote:
Originally Posted by Rising_Dusk
If you must use FirstOfGroup, do this:
Collapse JASS:
loop
    set SomeUnit = FirstOfGroup(MyGroup)
    exitwhen SomeUnit == null
    //Do stuff
    call GroupRemoveUnit(MyGroup, SomeUnit)
endloop
I have a question about that. When we remove a unit using FirstOfGroup, doesn't the first unit section of that of that group not move everything up so that the second unit becomes the first unit of that group? Er... That probably doesn't make any sense. Let me make an example. Let's say we have this; a group of units:

Group A
1. Unit 1
2. Unit 2
3. Unit 3

So, if we remove a unit using FirstOfGroup, does the group do this?

Group A
1. [Empty]
2. Unit 2
3. Unit 3

Or this?

Group A
1. Unit 2
2. Unit 3
3. [Empty]

If the first example is true, then everytime you try to use FirstOfGroup after the first time will just return null.
10-05-2009, 02:57 AM#11
Earth-Fury
Quote:
Originally Posted by Ignitedstar
I have a question about that. When we remove a unit using FirstOfGroup, doesn't the first unit section of that of that group not move everything up so that the second unit becomes the first unit of that group? Er... That probably doesn't make any sense. Let me make an example. Let's say we have this; a group of units:

Group A
1. Unit 1
2. Unit 2
3. Unit 3

So, if we remove a unit using FirstOfGroup, does the group do this?

Group A
1. [Empty]
2. Unit 2
3. Unit 3

Or this?

Group A
1. Unit 2
2. Unit 3
3. [Empty]

If the first example is true, then everytime you try to use FirstOfGroup after the first time will just return null.

The second example is more apt. Removing a unit from a group will cause it to not be returned by FirstOfGroup. However, there are other issues with that function and thus the FoG looping construct.
10-05-2009, 03:03 AM#12
Ignitedstar
Thanks, Earth-Fury. By the way, if someone has the time, what exactly are the "other problems" with FirstOfGroup? Or, it is better to say that it is obsolete compared to other things like it, like ForGroup?

I think I remember asking this before... It was a long time ago and I don't remember, so: What if we want to cast a single target spell on multiple units in the same instance? Last time I checked, I don't think a dummy unit can cast Entangling Roots on 5 units at the same time. Not to mention that it's nigh impossible to do ourselves. Isn't this when FirstOfGroup becomes useful? There's gotta be something I don't know.
10-05-2009, 03:09 AM#13
Anopob
Not to jack the thread but if I use:
Collapse JASS:
    local unit u
    local integer i = 1
    local integer loops
    local group g = CreateGroup()
    // get the group here
    set loops = CountUnitsInGroup (g)

    loop
        exitwhen i > loops
            set u = FirstOfGroup (g)
            // actions
            call GroupRemoveUnit (g, u)
            set i = i + 1
    endloop
besides the now obvious problems pointed out, would this work for most things? Or is the only problem the creation of 2 unnecessary integer variables? I'm not sure why but I've been doing most group loops like this, until late which I now use ForGroup().
10-05-2009, 03:22 AM#14
grim001
There is nothing wrong with FoG loops when used correctly, and they are often more appropriate than ForGroup when you need to retain the locals. Using globals to transfer the data is a pain unless you really need to avoid emptying the group.

If you immediately populate then enumerate through a group, there will be no shadow references. (Example: GroupEnum then FoG loop through the results.) If you have a group that's hanging around for more than an instant, a construct other than a group may be more appropriate.

And for the record, Dusk's implementation of the FoG loop is the correct one. The others have senseless extra operations.
10-05-2009, 05:08 AM#15
Anachron
Quote:
Originally Posted by Anitarf
Why do you need that extra boolean e? An exitwhen true statement under the else actions would suffice.
Well, basicly when I get an false return or something like that, I want to be able to skip the loop just with setting e to true.

The other implementation I did is also for the most pain I think, but its how I do advanced loops without removing user functionality.
And I think a small loop is better as ForGroup, imo.