# sprite group doesn't support indexing

I have a sprite group created with pygame.sprite.Group() (and add sprites to it with the add method)

How would I retrieve the nth sprite in this group?

Code like this does not work:

mygroup = pygame.sprite.Group(mysprite01)
print mygroup[n].rect


It returns the error: group object does not support indexing.

For the moment I'm using the following function:

def getSpriteByPosition(position,group):
for index,spr in enumerate(group):
if (index == position):
return spr
return False


Although working, it just doesn't seem right...

Is there a cleaner way to do this?

EDIT: I mention a "position" and index but it's not important actually, returning any single sprite from the group is enough

• Actually not anymore. I'm keeping the sprite group as I don't need to shuffle it anymore. – user3956 May 2 '11 at 9:32
• If you continue down this path of madness, at least update getSpriteByPosition to return None instead of False - False is equal to integer 0, which is a valid index. – user744 May 2 '11 at 13:47

What do you need the index for? Since sprites are hashed, the index is not stable; since you can't use it to easily find the sprite again, I don't know why you'd want to store it; and since you can't easily get from a sprite to an index I don't know how you got it in the first place.

If you need a reference to a sprite, reference the sprite itself, not its index.

• I'm not trying to index sprites inside a group. I just want to get the first or second sprite in the group, whatever it is and whenever it has been added to the group. (thanks for return None) – user3956 May 2 '11 at 13:58
• Groups are not ordered so "the first sprite in the group" is a useless designator. What you probably actually want is "the player sprite" or "the enemy ship" or something. Store those when you make them, don't rely on being able to pull them back out of a group by the weakest handle imaginable. – user744 May 2 '11 at 14:03
• hmm, it looks very well ordered to me. As a test I tried removing a sprite from its group (and printing the sprites names in the group before and after removing it) the sprites order is kept and I can get any sprite inside the group by "position" with the code above... but I understand a sprite group is here to keep all the "similar" sprites together for easier update and not to index them. – user3956 May 2 '11 at 14:18
• Removing a sprite is guaranteed, at the very least, to shift all the objects past it down by one. Removing many elements may make the dictionary shrink, rehashing. Adding elements is guaranteed to make the dictionary grow, rehashing. Indices into the key view/list - which are what you get when you make indices into the sprite group - are not reliable. – user744 May 2 '11 at 14:25
• Understood and agreed. Note that what I want to do is take any single sprite from the group. The code above does that and is not an aberration. If there's a better solution to achieve this, I will accept it. (in the question I mention a "position" or index but it's not important actually, getting any single sprite from the group is enough) I'm wondering if your answer to the linked question (shuffle group) would not work for this purpose as well... – user3956 May 2 '11 at 15:53

You can save a reference to the sprite elsewhere. Game class might have a variable pointing to the player instance, as well as sprite list.

You can have a reference to one sprite, in multiple sprite groups. Ex: Starcraft unit selections, could use a unit_list of all unit sprites. And a sprite group for selected_units.

player = Unit()
units = pygame.sprite.Group()
units.add( Unit(), Unit() , player, Unit() )

# use player, by ref.
print player.rect
for unit in unit_group:
print unit.rect


If you really, truly, absolutely want access a sprite by index, you can do this:

third_sprite = mygroup.sprites()[2]


def getSpriteByPosition(position,group):
return group.sprites()[position]


Which throws IndexError if the index is not found. If you want to return None in that case, simply enclose the line with a try block:

def getSpriteByPosition(position,group):
try:
return group.sprites()[position]
except IndexError:
pass


But... quoting user744, "What do you need the index for?". Afterall, the index of a sprite changes when you add or remove sprites to that group. And even if you don't, Pygame does not guarantee the list order will be the same in each call. So what do you mean by the "3rd sprite in the group"? It may be the 3rd now, but the 5th or 2nd later. How useful is that for you?

Simply put:

Being the nth sprite in a group means absolutely nothing !

(as a side note, position is a poor name for an index, as it might get confused as the sprite (x,y) position on screen)

Another sidenote: try to think OO. Instead of a function that receives a group as argument, subclass Group and create a custom method, so you can use it like mygroup.getSpriteByPosition(3)

As others have already said, you should probably refer to a sprite by something else then its order of addition to the group. I'll try to give some examples of uses both using a group and a regular list.

# sprite.Group

You can iterate over sprite.Group (or sprite.Group.sprites() - both give you the same) and check each sprite against some criteria.

Should you need to remove "dead" sprites, for example, you could use:

wanted_sprites = [sprite for sprite in mygroup if not sprite.alive]
# replace .alive with whatever condition you need
for sprite in wanted_sprites:
sprite.do_something()


or simply:

   [mygroup.remove(sprite) for sprite in mygroup if not sprite.alive]


# list

However, if you really need to keep a sprite's position in a list, why not just use a regular list? Instead of using mygroup.update() (one of the sprite.Group functions) you would have to use:

[sprite.update() for sprite in my_sprite_list]


or

[sprite.update() for sprite in my_sprite_list if sprite.visible]  # or whatever condition


For collisions, what really matters is the sprite.rect anyway, so you could check if a sprite collides with the last sprite of your list with:

some_sprite.rect.colliderect(my_sprite_list[-1].rect)


I've tried to say something about different possible needs to deal sprite.Group/list, but, in the end, you should consider your specific needs (and possible future needs) to decide what to do:

• change your logic to use a sprite.Group (changing the way you search for sprites);
• or change your logic to use a list of sprites (replacing the few functions that the Group has with your own).