Python Forum
Organizing list of objects by attribute - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: Organizing list of objects by attribute (/thread-24835.html)



Organizing list of objects by attribute - scarney1988 - Mar-06-2020

Hey guys/gals,

I have been working on my first python project of modelling a deck of standard playing cards. I am hoping to program a basic card game and then begin making a GUI for it.

I am stuck on getting the players hand organized. The card class has two attributes: value, suit. I would like to organize by 'value' so that I can come back check for pairs, 3 of a kind, etc...

Also, I just started reviewing PEP-8 recently. So I will be reorganizing things after its all functional as a learning exercise.

What do you guys/gals recommend

from Card import Card

class Deck:
    def __init__(self):
        self.deck_of_cards=[]
                         
    def initialize_deck(self):
        suits = ["Hearts", "Clubs", "Spades", "Diamonds"]
        values = ["Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"]
                    
        for suit in suits:
            for value in values:
                temp_card = Card()          #create a temporary card for each iteration
                                 
                temp_card.setvalue(value)   #set value and suit of temporary card prior to storage
                temp_card.setsuit(suit)
                
                self.deck_of_cards.append(temp_card)    #store card in the Deck object 
            
    def shuffle_deck(self):
        import random     #Import "random" module to gain access to "random.shuffle()"
        random.shuffle(self.deck_of_cards)
        
    def draw_card(self):
        temp_card = self.deck_of_cards.pop()
        return(temp_card)
    
    def load_card(self, temp_card):
        self.deck_of_cards.append(temp_card)
class Card:

    def __init__(self):
        self.value = "UNASSIGNED VALUE"
        self.suit = "UNASSIGNED SUIT"
    
    #def __init__(self, newvalue, newsuit):
        #self.value = newvalue
        #self.suit = newsuit
        
    def getvalue(self):
        return(self.value)
    
    def getsuit(self):
        return(self.suit)
    
    def setvalue(self, new_value):
        self.value=new_value
        
    def setsuit(self, new_suit):
        self.suit=new_suit
        
    def identify_card(self):
        print(self.getvalue(), "of", self.getsuit())
from Deck import Deck
from Card import Card

class Hand:
   
    def __init__(self):
        self.cards_in_hand = []
        
    def look_hand(self):
        for card in self.cards_in_hand:
            card.identify_card()
    
    def draw_card(self, deck):
        self.cards_in_hand.append(deck.draw_card())
        
    #def give_card(self):
        #FUNCTION WILL REMOVE A SPECIFIC CARD FROM HAND.CARDS_IN_HAND[].
        #FUNCTION WILL RECIEVE A NUMBER WHICH CORRELATES TO THE INDEX LOCATION OF THE
        #CARD TO BE RETURNED BY THE FUNCTION
        
    #def sort_hand(self):
        #FUNCTION WILL ORDER THE HAND BY VALUE OF THE CARDS.
    
    #def check_hand(self):
        #FUNCTION WILL RETURN AN INTEGER WHICH CORRESPONDS TO HIGHEST CHANCE TO WIN
        #AND AN INTEGER WHICH CORRESPONDS TO THE HIGH CARD OF THE HAND,
        # HIGH CARD   = 0
        # PAIR        = 1
        # TWO PAIR    = 2
        # 3 OF A KIND = 3
        # STRAIGHT    = 4
        # FLUSH       = 5
        # FULL HOUSE  = 6
        # 4 OF A KIND = 7
        # STR8T FLUSH = 8
        # ROYAL FLUSH = 9
        # 4 OF A KIND = 3
        # HIGH CARD: 2 = [0], 3 = [1] ... ACE = [13] 



RE: Organizing list of objects by attribute - stullis - Mar-06-2020

To sort by an attribute, you can use the sorted() built-in function.

As for the code, I have a couple recommendations. You already have a commented out implementation of a better Card so I would get rid of the first one and the setter methods. You'll see why in a moment. Also, instead of Card.identify_card(), make use of the __str__() and __repr__() dunder methods (this is more advanced, but the implementation is easy and you can learn something new!). These methods work with the print() function to provide a custom output for each instance.

class Card:
 
    def __init__(self, suit, value):
        self.value = value
        self.suit = suit
     
    def getvalue(self):
        return(self.value)
     
    def getsuit(self):
        return(self.suit)
         
    def __str__(self):
        return self.getvalue() + " of " + self.getsuit()

    def __repr__(self):
        return self.__str__()
With those changes, we can make an improvement to Deck.initialize_deck(). First, give it the same treatment with Deck.__init__() to pass in the suits and values - this makes the Deck more versatile. Then, use a list comprehension (again, more advanced) to make the cards. List comprehensions are faster than loops and more pythonic. Then, add method calls to Deck.initialize_deck() and Deck.shuffle_deck() to Deck.__init__() so it's ready for dealing as soon as it's initialized.

import random
from Card import Card

class Deck:
    def __init__(self, suits, values):
        self.deck_of_cards=[]
        self.suits = suits
        self.values = values
        self.initialize_deck()
        self.shuffle_deck()
                          
    def initialize_deck(self):
        self.deck_of_cards = [Card(s, v) for s in suits for v in values]

    def shuffle_deck(self):
        random.shuffle(self.deck_of_cards)
         
    def draw_card(self):
        return self.deck_of_cards.pop()
     
    def load_card(self, temp_card):
        self.deck_of_cards.append(temp_card)



RE: Organizing list of objects by attribute - scarney1988 - Mar-07-2020

Thank you. That was a great response. Very very helpful.

I had initially went with the set methods because I wanted to eventually add in a Joker card which the user could input value and suit. I guess I could just use something like the following to achieve that:

def assign_joker(joker_card):
# FUNCTION CALLED TO TAKE USER INPUT FOR CARD VALUE / SUIT (OMITTED), THEN RETURN THE CARD
# PROPERLY ASSIGNED AS FOLLOWS

     return (joker_card = Card(chosen_value, chosen_suit))



RE: Organizing list of objects by attribute - scarney1988 - Mar-11-2020

(Mar-06-2020, 03:20 PM)stullis Wrote: To sort by an attribute, you can use the sorted() built-in function.

Thank you. I was able to code the following to accomplish my task:

self.cards_in_hand = sorted(self.cards_in_hand, key=lambda x: x.value, reverse=True)
Thanks again,
Sean