Select the object with a larger value of a specific attribute
I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.
I have a working code outlined here:
import random
class UserGroup:
def __init__(self, users):
self.user_list = users
def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2
class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma
class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity
class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
users = UserGroup([jared, poptart, kaos, magda])
for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())
The example output is shown below:
Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3
As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight()
method inside the Battle
class. I don't think the large sequence of if
statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed)
but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.
python
add a comment |
I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.
I have a working code outlined here:
import random
class UserGroup:
def __init__(self, users):
self.user_list = users
def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2
class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma
class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity
class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
users = UserGroup([jared, poptart, kaos, magda])
for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())
The example output is shown below:
Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3
As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight()
method inside the Battle
class. I don't think the large sequence of if
statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed)
but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.
python
Tryself.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.
– John Szakmeister
Jan 2 at 1:27
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
why not create adef who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?
– Patrick Artner
Jan 2 at 1:34
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)
– John Szakmeister
Jan 2 at 9:31
add a comment |
I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.
I have a working code outlined here:
import random
class UserGroup:
def __init__(self, users):
self.user_list = users
def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2
class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma
class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity
class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
users = UserGroup([jared, poptart, kaos, magda])
for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())
The example output is shown below:
Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3
As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight()
method inside the Battle
class. I don't think the large sequence of if
statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed)
but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.
python
I just started learning python so I'm not familiar with the various tricks or tools, or the proper way to word my question. Because of that, I was unable to find previous questions that do what I am looking for.
I have a working code outlined here:
import random
class UserGroup:
def __init__(self, users):
self.user_list = users
def random_users(self):
self.random_1 = random.choice(self.user_list)
self.random_2 = self.random_1
while self.random_2 == self.random_1:
self.random_2 = random.choice(self.user_list)
return self.random_1, self.random_2
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
class Jared(User):
def fight_stat(self):
self.attack = self.strength + self.intelligence
self.defense = self.constitution * 2
self.speed = self.dexterity / 2
class Poptart(User):
def fight_stat(self):
self.attack = self.strength + self.dexterity
self.defense = self.dexterity
self.speed = self.dexterity + self.charisma
class Kaos(User):
def fight_stat(self):
self.attack = self.dexterity + self.wisdom
self.defense = self.wisdom * 2
self.speed = self.dexterity
class Magda(User):
def fight_stat(self):
self.attack = self.intelligence + self.charisma
self.defense = self.dexterity + self.charisma
self.speed = self.dexterity + self.constitution / 2
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
if self.user1.speed > self.user2.speed:
self.attacker = self.user1
self.defender = self.user2
elif self.user2.speed > self.user1.speed:
self.attacker = self.user2
self.defender = self.user1
elif self.user1.dexterity > self.user2.dexterity:
self.attacker = self.user1
self.defender = self.user2
else:
self.attacker = self.user2
self.defender = self.user1
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
# HERE STARTS BATTLE CODE
jared = Jared('Jarebear', {'strength': 7, 'constitution': 6, 'dexterity': 6, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
poptart = Poptart('Yung SLizzy', {'strength': 4, 'constitution': 5, 'dexterity': 10, 'intelligence': 7, 'wisdom': 5, 'charisma': 7})
kaos = Kaos('Kung Cows', {'strength': 8, 'constitution': 7, 'dexterity': 6, 'intelligence': 4, 'wisdom': 7, 'charisma': 4})
magda = Magda('Meghan M', {'strength': 7, 'constitution': 5, 'dexterity': 7, 'intelligence': 8, 'wisdom': 5, 'charisma': 5})
users = UserGroup([jared, poptart, kaos, magda])
for i in range(1,4):
print("Battle number", i)
battle = Battle(*users.random_users())
print("The winner is: ", battle.fight())
The example output is shown below:
Battle number 1
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 2
Jarebear and Kung Cows have entered the fight!
The winner is: Kung Cows
Battle number 3
As I have written it, the code performs as expected. However, I am concerned about the way that I've implemented the fight()
method inside the Battle
class. I don't think the large sequence of if
statements is the proper way to say "user with higher speed attacks first". Logically, I just need a statement that is like self.attacker = max(self.user1.speed, self.user2.speed)
but the attacker is set to the user, not the user's speed. However, I don't know how to accomplish this in one or two lines of code in python.
python
python
edited Jan 2 at 1:56
Mad Physicist
38k1674107
38k1674107
asked Jan 2 at 1:14
Jared CJared C
230213
230213
Tryself.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.
– John Szakmeister
Jan 2 at 1:27
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
why not create adef who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?
– Patrick Artner
Jan 2 at 1:34
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)
– John Szakmeister
Jan 2 at 9:31
add a comment |
Tryself.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.
– John Szakmeister
Jan 2 at 1:27
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
why not create adef who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?
– Patrick Artner
Jan 2 at 1:34
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)
– John Szakmeister
Jan 2 at 9:31
Try
self.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.– John Szakmeister
Jan 2 at 1:27
Try
self.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.– John Szakmeister
Jan 2 at 1:27
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
why not create a
def who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?– Patrick Artner
Jan 2 at 1:34
why not create a
def who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?– Patrick Artner
Jan 2 at 1:34
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:
self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)– John Szakmeister
Jan 2 at 9:31
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:
self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)– John Szakmeister
Jan 2 at 9:31
add a comment |
7 Answers
7
active
oldest
votes
Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.
class Battle:
# snipped some code
@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you like a brain teaser you could as well do:
@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).
Doku:
Does Python have a ternary conditional operator? (forreturn .. if ... else ...
)- sorted(... with key and reversed ...)
- Why are Python lambdas useful?
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
add a comment |
The min
and max
functions accept a key
function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:
max(self.user1, self.user2, key=lambda item: item.speed)
For a large number of comparisons, this can be rewritten as
from operator import attrgetter
speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb'
because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2]
.
So to use the dexterity
attribute as a fallback for equal speeds, do
max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))
OR
speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)
add a comment |
If you want to use max
with your objects, you can implement __gt__
com compare them (and __eq__
for consistency). So your User
class could look like this:
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
def __eq__(self, other):
return self.speed == other.speed and self.dexterity == other.dexterity
def __gt__(self, other):
return self.speed > other.speed or self.dexterity > other.dexterity
This implementation would allow you to use max
and min
to define the attacker
and defender
in the Battle
class.
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = max(self.user1, self.user2)
self.defender = min(self.user1, self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
add a comment |
I just need a statement that is like self.attacker =
max(self.user1.speed, self.user2.speed) but the attacker is set to the
user, not the user's speed.
You can use
from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
This will return the user
(not speed
) has max speed
If you have more than 2 users, you can also pass list
More information about attrgetter
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
add a comment |
You can indeed use max() to get the user
with most speed.
The way of doing it is with the key
argument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.
def score(user):
return user.speed
fastest_user = max(list_of_users, key=score)
The most common is to pass an anonymous lambda function which you define with the syntax:
lambda var1, var2: expression
So the code would look like:
fastest_user = max(list_of_users, key=lambda user: user.speed)
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just dofrom random import shuffle
and use that function to mess the list before.
– Jeacom
Jan 2 at 1:43
add a comment |
Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
@staticmethod
def _compare_attributes(user1: User, user2: User, attribute: str):
if getattr(user1, attribute) != getattr(user2, attribute):
return max(
[user1, user2],
key=lambda user: getattr(user, attribute)
)
def get_attacker(self):
"""
Returns attacker based on attribute comparison
:return: User
"""
default_attacker = self.user2
attribute_priority_order = [
'speed',
'dexterity'
]
for attribute in attribute_priority_order:
attacker = self._compare_attributes(
user1=self.user1,
user2=self.user2,
attribute=attribute
)
if attacker:
return attacker
return default_attacker
def get_defender(self):
"""
User in the battle that isn't the attacker.
:return: User
"""
for user in [self.user1, self.user2]:
if str(user) != str(self.attacker):
return user
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = self.get_attacker()
self.defender = self.get_defender()
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
With a little extra abstraction, _compare_attributes
method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.
add a comment |
How about using the fact that python lists compare so your ability measure is:
def ability(user):
return (user.speed, user.dexterity)
Your winning criteria is:
def winner(attacker, defender):
return attacker.attack > defender.defense
And the fight becomes:
def fight(a, b):
return winner(a, b) if ability(a) >= ability(b) else winner(b, a)
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54000219%2fselect-the-object-with-a-larger-value-of-a-specific-attribute%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
7 Answers
7
active
oldest
votes
7 Answers
7
active
oldest
votes
active
oldest
votes
active
oldest
votes
Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.
class Battle:
# snipped some code
@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you like a brain teaser you could as well do:
@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).
Doku:
Does Python have a ternary conditional operator? (forreturn .. if ... else ...
)- sorted(... with key and reversed ...)
- Why are Python lambdas useful?
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
add a comment |
Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.
class Battle:
# snipped some code
@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you like a brain teaser you could as well do:
@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).
Doku:
Does Python have a ternary conditional operator? (forreturn .. if ... else ...
)- sorted(... with key and reversed ...)
- Why are Python lambdas useful?
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
add a comment |
Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.
class Battle:
# snipped some code
@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you like a brain teaser you could as well do:
@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).
Doku:
Does Python have a ternary conditional operator? (forreturn .. if ... else ...
)- sorted(... with key and reversed ...)
- Why are Python lambdas useful?
Creating small methods that concentrate logic is no "overhead". They are easy to understand, and do not need to change for lots of reasons - hence they are done, testet and unchanged most of the time.
class Battle:
# snipped some code
@staticmethod
def get_attacker_defender(u1, u2):
"""Returs tuple (attacker,defender) based on given user."""
if u1.speed > u2.speed:
return u1,u2
elif u2.speed > u1.speed:
return u2,u1
# probably cleaner to stay with elif: ... else ... but this is shorter
return (u1,u2) if u1.dexterity > u2.dexterity else (u2,u1)
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker, self.defender = Battle.get_attacker_defender(self.user1,self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you like a brain teaser you could as well do:
@staticmethod
def get_attacker_defender(u1,u2):
return sorted( [u1,u2], key = lambda u:(u.speed,u.dexterity), reverse=True)
which leverages tuple-sorting that sorts based on the 1st element, and when the 1st ones are equal on the 2nd element of the tuple. If both are equal the order stays as is (stable sorting with Timsort).
Doku:
Does Python have a ternary conditional operator? (forreturn .. if ... else ...
)- sorted(... with key and reversed ...)
- Why are Python lambdas useful?
edited Jan 2 at 1:55
answered Jan 2 at 1:42
Patrick ArtnerPatrick Artner
25k62443
25k62443
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
add a comment |
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
If I can learn to understand and use the "brain teaser" then I think I will become a better programmer
– Jared C
Jan 2 at 1:51
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
@JaredC you might - but it will make the code only shorter - not cleaner
– Patrick Artner
Jan 2 at 1:52
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
There has been a wealth of knowledge offered in response to my question, and I think I can take things from every answer and improve my understanding of python. This is the answer which best fits my specific needs, although many of the answers presented could be used to achieve the desired results.
– Jared C
Jan 2 at 12:54
add a comment |
The min
and max
functions accept a key
function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:
max(self.user1, self.user2, key=lambda item: item.speed)
For a large number of comparisons, this can be rewritten as
from operator import attrgetter
speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb'
because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2]
.
So to use the dexterity
attribute as a fallback for equal speeds, do
max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))
OR
speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)
add a comment |
The min
and max
functions accept a key
function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:
max(self.user1, self.user2, key=lambda item: item.speed)
For a large number of comparisons, this can be rewritten as
from operator import attrgetter
speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb'
because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2]
.
So to use the dexterity
attribute as a fallback for equal speeds, do
max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))
OR
speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)
add a comment |
The min
and max
functions accept a key
function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:
max(self.user1, self.user2, key=lambda item: item.speed)
For a large number of comparisons, this can be rewritten as
from operator import attrgetter
speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb'
because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2]
.
So to use the dexterity
attribute as a fallback for equal speeds, do
max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))
OR
speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)
The min
and max
functions accept a key
function that tells them how to compare the inputs. The key accepts each input and returns the actual value to compare:
max(self.user1, self.user2, key=lambda item: item.speed)
For a large number of comparisons, this can be rewritten as
from operator import attrgetter
speed_key = attrgetter('speed')
max(self.user1, self.user2, key=speed_key)
If you have equal speeds, you can decide to compare using a different attribute. This is done by understanding that Python sequences are compared in lexicographixal order. This is easiest to understand with strings, since it's basically just dictionary order: e.g. 'abc' > 'abb'
because each element is compared in order. The same applies to lists and tuples: [1, 2, 3] > [1, 2, 2]
.
So to use the dexterity
attribute as a fallback for equal speeds, do
max(self.user1, self.user2, key=lambda item: (item.speed, item.dexterity))
OR
speedex_key = attrgetter('speed', 'dexterity')
max(self.user1, self.user2, key=speedex_key)
answered Jan 2 at 1:54
Mad PhysicistMad Physicist
38k1674107
38k1674107
add a comment |
add a comment |
If you want to use max
with your objects, you can implement __gt__
com compare them (and __eq__
for consistency). So your User
class could look like this:
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
def __eq__(self, other):
return self.speed == other.speed and self.dexterity == other.dexterity
def __gt__(self, other):
return self.speed > other.speed or self.dexterity > other.dexterity
This implementation would allow you to use max
and min
to define the attacker
and defender
in the Battle
class.
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = max(self.user1, self.user2)
self.defender = min(self.user1, self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
add a comment |
If you want to use max
with your objects, you can implement __gt__
com compare them (and __eq__
for consistency). So your User
class could look like this:
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
def __eq__(self, other):
return self.speed == other.speed and self.dexterity == other.dexterity
def __gt__(self, other):
return self.speed > other.speed or self.dexterity > other.dexterity
This implementation would allow you to use max
and min
to define the attacker
and defender
in the Battle
class.
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = max(self.user1, self.user2)
self.defender = min(self.user1, self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
add a comment |
If you want to use max
with your objects, you can implement __gt__
com compare them (and __eq__
for consistency). So your User
class could look like this:
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
def __eq__(self, other):
return self.speed == other.speed and self.dexterity == other.dexterity
def __gt__(self, other):
return self.speed > other.speed or self.dexterity > other.dexterity
This implementation would allow you to use max
and min
to define the attacker
and defender
in the Battle
class.
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = max(self.user1, self.user2)
self.defender = min(self.user1, self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
If you want to use max
with your objects, you can implement __gt__
com compare them (and __eq__
for consistency). So your User
class could look like this:
class User:
def __init__(self, nickname, stats):
self.nickname = nickname
self.strength = stats['strength']
self.constitution = stats['constitution']
self.dexterity = stats['dexterity']
self.intelligence = stats['intelligence']
self.wisdom = stats['wisdom']
self.charisma = stats['charisma']
def __repr__(self):
return self.nickname
def __eq__(self, other):
return self.speed == other.speed and self.dexterity == other.dexterity
def __gt__(self, other):
return self.speed > other.speed or self.dexterity > other.dexterity
This implementation would allow you to use max
and min
to define the attacker
and defender
in the Battle
class.
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = max(self.user1, self.user2)
self.defender = min(self.user1, self.user2)
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
answered Jan 2 at 2:34
Renan IvoRenan Ivo
1,266917
1,266917
add a comment |
add a comment |
I just need a statement that is like self.attacker =
max(self.user1.speed, self.user2.speed) but the attacker is set to the
user, not the user's speed.
You can use
from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
This will return the user
(not speed
) has max speed
If you have more than 2 users, you can also pass list
More information about attrgetter
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
add a comment |
I just need a statement that is like self.attacker =
max(self.user1.speed, self.user2.speed) but the attacker is set to the
user, not the user's speed.
You can use
from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
This will return the user
(not speed
) has max speed
If you have more than 2 users, you can also pass list
More information about attrgetter
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
add a comment |
I just need a statement that is like self.attacker =
max(self.user1.speed, self.user2.speed) but the attacker is set to the
user, not the user's speed.
You can use
from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
This will return the user
(not speed
) has max speed
If you have more than 2 users, you can also pass list
More information about attrgetter
I just need a statement that is like self.attacker =
max(self.user1.speed, self.user2.speed) but the attacker is set to the
user, not the user's speed.
You can use
from operator import attrgetter
...
self.attacker = max(self.user1, self.user2, key=attrgetter('speed'))
This will return the user
(not speed
) has max speed
If you have more than 2 users, you can also pass list
More information about attrgetter
answered Jan 2 at 1:30
user3790180user3790180
10819
10819
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
add a comment |
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
add a comment |
You can indeed use max() to get the user
with most speed.
The way of doing it is with the key
argument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.
def score(user):
return user.speed
fastest_user = max(list_of_users, key=score)
The most common is to pass an anonymous lambda function which you define with the syntax:
lambda var1, var2: expression
So the code would look like:
fastest_user = max(list_of_users, key=lambda user: user.speed)
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just dofrom random import shuffle
and use that function to mess the list before.
– Jeacom
Jan 2 at 1:43
add a comment |
You can indeed use max() to get the user
with most speed.
The way of doing it is with the key
argument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.
def score(user):
return user.speed
fastest_user = max(list_of_users, key=score)
The most common is to pass an anonymous lambda function which you define with the syntax:
lambda var1, var2: expression
So the code would look like:
fastest_user = max(list_of_users, key=lambda user: user.speed)
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just dofrom random import shuffle
and use that function to mess the list before.
– Jeacom
Jan 2 at 1:43
add a comment |
You can indeed use max() to get the user
with most speed.
The way of doing it is with the key
argument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.
def score(user):
return user.speed
fastest_user = max(list_of_users, key=score)
The most common is to pass an anonymous lambda function which you define with the syntax:
lambda var1, var2: expression
So the code would look like:
fastest_user = max(list_of_users, key=lambda user: user.speed)
You can indeed use max() to get the user
with most speed.
The way of doing it is with the key
argument which you use to pass a custom scoring function that takes each object and returns a orderable value like a float or int.
def score(user):
return user.speed
fastest_user = max(list_of_users, key=score)
The most common is to pass an anonymous lambda function which you define with the syntax:
lambda var1, var2: expression
So the code would look like:
fastest_user = max(list_of_users, key=lambda user: user.speed)
edited Jan 2 at 1:36
answered Jan 2 at 1:30
JeacomJeacom
254
254
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just dofrom random import shuffle
and use that function to mess the list before.
– Jeacom
Jan 2 at 1:43
add a comment |
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just dofrom random import shuffle
and use that function to mess the list before.
– Jeacom
Jan 2 at 1:43
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Is there a way to have it check the dexterity score (or just select one at random) if the speed of the users is the same?
– Jared C
Jan 2 at 1:36
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do
from random import shuffle
and use that function to mess the list before.– Jeacom
Jan 2 at 1:43
Max will just return the first element if all the users have the same speed, so shuffling the list before should do the trick. for that just do
from random import shuffle
and use that function to mess the list before.– Jeacom
Jan 2 at 1:43
add a comment |
Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
@staticmethod
def _compare_attributes(user1: User, user2: User, attribute: str):
if getattr(user1, attribute) != getattr(user2, attribute):
return max(
[user1, user2],
key=lambda user: getattr(user, attribute)
)
def get_attacker(self):
"""
Returns attacker based on attribute comparison
:return: User
"""
default_attacker = self.user2
attribute_priority_order = [
'speed',
'dexterity'
]
for attribute in attribute_priority_order:
attacker = self._compare_attributes(
user1=self.user1,
user2=self.user2,
attribute=attribute
)
if attacker:
return attacker
return default_attacker
def get_defender(self):
"""
User in the battle that isn't the attacker.
:return: User
"""
for user in [self.user1, self.user2]:
if str(user) != str(self.attacker):
return user
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = self.get_attacker()
self.defender = self.get_defender()
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
With a little extra abstraction, _compare_attributes
method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.
add a comment |
Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
@staticmethod
def _compare_attributes(user1: User, user2: User, attribute: str):
if getattr(user1, attribute) != getattr(user2, attribute):
return max(
[user1, user2],
key=lambda user: getattr(user, attribute)
)
def get_attacker(self):
"""
Returns attacker based on attribute comparison
:return: User
"""
default_attacker = self.user2
attribute_priority_order = [
'speed',
'dexterity'
]
for attribute in attribute_priority_order:
attacker = self._compare_attributes(
user1=self.user1,
user2=self.user2,
attribute=attribute
)
if attacker:
return attacker
return default_attacker
def get_defender(self):
"""
User in the battle that isn't the attacker.
:return: User
"""
for user in [self.user1, self.user2]:
if str(user) != str(self.attacker):
return user
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = self.get_attacker()
self.defender = self.get_defender()
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
With a little extra abstraction, _compare_attributes
method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.
add a comment |
Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
@staticmethod
def _compare_attributes(user1: User, user2: User, attribute: str):
if getattr(user1, attribute) != getattr(user2, attribute):
return max(
[user1, user2],
key=lambda user: getattr(user, attribute)
)
def get_attacker(self):
"""
Returns attacker based on attribute comparison
:return: User
"""
default_attacker = self.user2
attribute_priority_order = [
'speed',
'dexterity'
]
for attribute in attribute_priority_order:
attacker = self._compare_attributes(
user1=self.user1,
user2=self.user2,
attribute=attribute
)
if attacker:
return attacker
return default_attacker
def get_defender(self):
"""
User in the battle that isn't the attacker.
:return: User
"""
for user in [self.user1, self.user2]:
if str(user) != str(self.attacker):
return user
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = self.get_attacker()
self.defender = self.get_defender()
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
With a little extra abstraction, _compare_attributes
method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.
Here is an answer that separates the logic as was mentioned above, and uses your original max desire. The benefit to this solution is that logic to determine first attack could be easily refactored. Simply change the order (or add attributes to) attribute_priority_order
class Battle:
def __init__(self, user1, user2):
self.user1 = user1
self.user2 = user2
print(user1, "and", user2, "have entered the fight!")
@staticmethod
def _compare_attributes(user1: User, user2: User, attribute: str):
if getattr(user1, attribute) != getattr(user2, attribute):
return max(
[user1, user2],
key=lambda user: getattr(user, attribute)
)
def get_attacker(self):
"""
Returns attacker based on attribute comparison
:return: User
"""
default_attacker = self.user2
attribute_priority_order = [
'speed',
'dexterity'
]
for attribute in attribute_priority_order:
attacker = self._compare_attributes(
user1=self.user1,
user2=self.user2,
attribute=attribute
)
if attacker:
return attacker
return default_attacker
def get_defender(self):
"""
User in the battle that isn't the attacker.
:return: User
"""
for user in [self.user1, self.user2]:
if str(user) != str(self.attacker):
return user
def fight(self):
self.user1.fight_stat()
self.user2.fight_stat()
self.attacker = self.get_attacker()
self.defender = self.get_defender()
if self.attacker.attack > self.defender.defense:
return self.attacker
elif self.defender.attack > self.attacker.defense:
return self.defender
else:
return "Draw"
With a little extra abstraction, _compare_attributes
method could be recycled to determine the winner as well maybe with an optional second attribute. The return from this method is optionally a user if there is no tie.
edited Jan 2 at 2:16
answered Jan 2 at 2:10
Andrew RiessAndrew Riess
10423
10423
add a comment |
add a comment |
How about using the fact that python lists compare so your ability measure is:
def ability(user):
return (user.speed, user.dexterity)
Your winning criteria is:
def winner(attacker, defender):
return attacker.attack > defender.defense
And the fight becomes:
def fight(a, b):
return winner(a, b) if ability(a) >= ability(b) else winner(b, a)
add a comment |
How about using the fact that python lists compare so your ability measure is:
def ability(user):
return (user.speed, user.dexterity)
Your winning criteria is:
def winner(attacker, defender):
return attacker.attack > defender.defense
And the fight becomes:
def fight(a, b):
return winner(a, b) if ability(a) >= ability(b) else winner(b, a)
add a comment |
How about using the fact that python lists compare so your ability measure is:
def ability(user):
return (user.speed, user.dexterity)
Your winning criteria is:
def winner(attacker, defender):
return attacker.attack > defender.defense
And the fight becomes:
def fight(a, b):
return winner(a, b) if ability(a) >= ability(b) else winner(b, a)
How about using the fact that python lists compare so your ability measure is:
def ability(user):
return (user.speed, user.dexterity)
Your winning criteria is:
def winner(attacker, defender):
return attacker.attack > defender.defense
And the fight becomes:
def fight(a, b):
return winner(a, b) if ability(a) >= ability(b) else winner(b, a)
answered Jan 2 at 2:18
Mike RobinsMike Robins
1,297510
1,297510
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54000219%2fselect-the-object-with-a-larger-value-of-a-specific-attribute%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Try
self.attacker = max(self.user1, self.user2, key=lambda u: u.speed)
. The only issue is that it will favor user1 when the speed of user1 and user2 are the same.– John Szakmeister
Jan 2 at 1:27
in my if/else statements I have it look at the dexterity if speed happens to be the same. Any way to include that?
– Jared C
Jan 2 at 1:31
why not create a
def who_goes_first(user1,user2)
method - put your logic into it and if they draw, choose one randomly? cleans up your fight code, creates a funciton with low reason to change and makes it more obvious whats happening?– Patrick Artner
Jan 2 at 1:34
I felt if I move the if/else statements into yet another function, that I would just be over-engineering what should be a simple solution
– Jared C
Jan 2 at 1:35
@JaredC yes, just return a tuple of what you want out of the lambda function. In this case, it would be:
self.attacker = max(self.user1, self.user2, key=lambda u: (u.speed, u.dexterity))
I do recommend the suggestion about factoring the logic out into it's own method. As a seasoned developer (20+ years of experience), I would not call it over-engineering, I'd call it making it readable and providing logical separation of responsibilities. :-)– John Szakmeister
Jan 2 at 9:31