DarkLight
DarkLight

Reputation: 91

counting instances of a class based on attributes

Counting the number of instances of a specific attribute value

I have created a class, named: bird. Each instance of that class has two attributes:

The program simulates random encounters of two live birds, the birds change the value of life after each encounter. Once reaching 0, the bird is excluded from further interactions (i.e. dead).

After several iterations, I wish to know how many birds of each creed are "alive".

import random


class Bird:
    Doves = 100
    Crows = 100

    # Initializer / Instance Attributes
    def __init__(self, creed, life):
        self.creed = creed
        self.life = life


def slct_parties():
    first = random.randint(0, (Bird.Crows + Bird.Doves -1))
    second = random.randint(0, (Bird.Crows + Bird.Doves -1))
    while first == second or population[first].life < 1 or population[second].life < 1:
        first = random.randint(0, (Bird.Crows + Bird.Doves - 1))
        second = random.randint(0, (Bird.Crows + Bird.Doves - 1))
    return first, second


#   initiating Population
population = []

for bird in range(0, Bird.Crows):
    population.append(Bird('C', 100))

for bird in range(0, Bird.Doves):
    population.append(Bird('D', 100))

for x in range(1, 1000):
    Contest = slct_parties()
    l1 = population[Contest[0]].life
    l2 = population[Contest[1]].life
    # battle
    if population[Contest[0]].creed != population[Contest[0]].creed:
        if population[Contest[0]].creed == 'D':
            population[Contest[0]].life += 1
            population[Contest[1]].life += 1
        else:
            population[Contest[0]].life += -5
            population[Contest[1]].life += -10
    elif population[Contest[0]].creed == 'C':
        population[Contest[0]].life += 5
        population[Contest[1]].life += -20
    else:
        population[Contest[0]].life += -20
        population[Contest[1]].life += 5

    print("The battle was between {} number {} with {} life, and {} number {} with {} life"
        .format(population[Contest[0]].creed, Contest[0], population[Contest[0]].life, population[Contest[1]].creed,
        Contest[1], population[Contest[1]].life))

After 1,000 battles, some birds have died. How many birds? Which creed?

Short answer

def DeadConter(crd):
    dead = 0
    for bird in population:
        if bird.life <= 0 and bird.creed == crd:
            dead += 1
        else:
            pass
    return dead

Upvotes: 2

Views: 113

Answers (3)

new Q Open Wid
new Q Open Wid

Reputation: 2283

You can also define 2 values that both start at 0 before the definition of the class that count how many birds are dead, like adding one cDead += 1 when a bird becomes "dead". After the 1000 battles, subtract 100 from the first value and subtract 100 from the second value. You get then, how many bird of each creed are alive. You can also count how many birds of each creed are dead, like this.

import random

c_dead = 0
d_dead = 0

class Bird:
    Doves = 100
    Crows = 100

    # Initializer / Instance Attributes
    def __init__(self, creed, life):
        self.creed = creed
        self.life = life


def slct_parties():
    first = random.randint(0, (Bird.Crows + Bird.Doves -1))
    second = random.randint(0, (Bird.Crows + Bird.Doves -1))
    while first == second or population[first].life < 1 or population[second].life < 1:
        first = random.randint(0, (Bird.Crows + Bird.Doves - 1))
        second = random.randint(0, (Bird.Crows + Bird.Doves - 1))
    return first, second


#   initiating Population
population = []

for bird in range(0, Bird.Crows):
    population.append(Bird('C', 100))

for bird in range(0, Bird.Doves):
    population.append(Bird('D', 100))

for x in range(1, 1000):
    Contest = slct_parties()
    l1 = population[Contest[0]].life
    l2 = population[Contest[1]].life
    # battle
    if population[Contest[0]].creed != population[Contest[0]].creed:
        if population[Contest[0]].creed == 'D':
            population[Contest[0]].life += 1
            population[Contest[1]].life += 1
        else:
            population[Contest[0]].life += -5
            population[Contest[1]].life += -10
    elif population[Contest[0]].creed == 'C':
        population[Contest[0]].life += 5
        population[Contest[1]].life += -20
    else:
        population[Contest[0]].life += -20
        population[Contest[1]].life += 5

for bird in population:
    if bird.life <= 0:
        if bird.creed == "C":
            c_dead += 1
        elif bird.creed == "D":
            d_dead += 1
        else:
            print("Dead birds failed to count") # should never happen, this is a good check for bugs

print("The battle was between {} number {} with {} life, and {} number {} with {} life"
        .format(population[Contest[0]].creed, Contest[0], population[Contest[0]].life, population[Contest[1]].creed,
        Contest[1], population[Contest[1]].life))
#print dead birds here
print("Number of alive birds")
print(str(100-c_dead) + ": Doves" + " " + str(100-d_dead) + ": Crows")

I added the else line because this code is untested, I don't know if there are any bugs.

EDIT: The code has been tested now and I've changed a few lines to get it working.

Upvotes: 1

Carcigenicate
Carcigenicate

Reputation: 45736

If you want to count them after the fact and not keep running tallies, just iterate over the population:

c_dead = 0
d_dead = 0

for bird in population:
    if bird.life <= 0:  # The bird is dead
        if bird.creed == "c":
            c_dead += 1  # Figure out what creed it is and increment a counter

        else
            d_dead += 1

This could be cleaned up using a dictionary or some other container, but I think this is the simplest way to show the idea.


In the comments, you noted that you were looking for something along the lines of count(population, creed="c", life>0). That can't be achieved exactly, but you can use a list comprehension to filter out the birds you don't want to count.

c_dead = len([bird for bird in population if bird.creed == "c" and bird.life <= 0])

d_dead = len([bird for bird in population if bird.creed == "d" and bird.life <= 0])

I wouldn't recommend this way though. This requires two full iterations of the population, whereas the first only requires one. If this operation was frequent, and the populations was large, it could cause performance problems.

Upvotes: 1

PMM
PMM

Reputation: 376

Try adding an external variable before the init, initialize it at zero and increment its value by one in the init (+1 for every instance). Then create a function that checks if a bird has died or not and if so, decrease the value of the variable by one

Upvotes: 1

Related Questions