Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Breaking down instances of classes into lists, or: a better way to sum class variables?

Tags:

python

class

This is part of a project that I've been working on for a bit now. I'm having a hard time synthesizing the mental pseudocode with something I can actually write, largely due to personal misconceptions about how stuff works.

I'm tracking inventory for an imaginary fruit stand, using the following class:

class Fruit(object)
    def __init__(self,name,qty,price)
        self.color = str(color)
        self.qty = int(qty)
        self.price = float(price)

    def getName(self): return self.color
    def getQty(self): return self.qty
    def getPrice(self): return self.price
    def description(self): return self.color,self.qty,self.price

Objects in this class end up getting imported as values for keys of a dictionary. There can be multiple values for each key, stored in a list, such that when the dictionary is printed, it returns something like this (with line breaks for readability:)

Lemon: [(Yellow, 5, 2.99)]
Apple: [(Red, 10, 0.99), (Green, 9, 0.69)]
Cherry: [(White, 2, 5.99),(Red, 5, 5.99)]

I am trying now to end up getting the sum value of all bits of fruit on my imaginary fruit stand. My original thought was just to treat each value as a list, iterate through the list until I hit an integer, multiply the integer by the float in the index right behind it, and then add that quantity to a variable that had a running total; then move on to keep looking for another integer. Which would work great, if "index 1" of list "Cherry" weren't (Red, 5, 5.99) rather than (2).

So, a couple of questions.

  1. Every time I do something like this, where I have a dictonary with multiple values which are all class objects, each value is stored as a parenthetical (for lack of a better thing to call it.) Is that something that should be happening, or do I need to re-evaluate the way I am doing what I am doing, because I am causing that to happen?

  2. If I don't need to re-evaluate my choices here, is there a way to break down the "parentheticals" (for lack of a better thing to call them immediately coming to mind) to be able to treat the whole thing as a list?

  3. Is there a better way to do what I want to do that doesn't involve iterating through a list?

Thanks in advance. I have been fighting with various parts of this problem for a week.

like image 204
user2113818 Avatar asked Dec 20 '22 06:12

user2113818


2 Answers

Assuming a dictionary like this:

fruit_stand = {
    "Lemon": [(Yellow, 5, 2.99)],
    "Apple": [(Red, 10, 0.99), (Green, 9, 0.69)],
    "Cherry": [(White, 2, 5.99),(Red, 5, 5.99)]
}

You can actually just iterate over the dictionary to get its keys:

for fruit_name in fruit_stand:
    print fruit_name

# Lemon
# Apple
# Cherry
# NOTE: Order not guaranteed
# Cherry, Lemon, Apple are equally likely

You can then use the items method of the dictionary to get a tuple (what you are calling a "parenthetical") of key, value pairs:

for fruit_name, fruits in fruit_stand.items():
    print fruit_name, "=>", fruits

# Lemon => [(Yellow, 5, 2.99)]
# Apple => [(Red, 10, 0.99), (Green, 9, 0.69)]
# Cherry => [(White, 2, 5.99),(Red, 5, 5.99)]

lists (that's the bracketed []) are also iterable:

for fruit in [(White, 2, 5.99),(Red, 5, 5.99)]:
    print fruit

# (White, 2, 5.99)
# (Red, 5, 5.99)

So we can work with each fruits list to get access to our tuple:

for fruit_name, fruit_list in fruit_stand.items():
    # Ignore fruit_name and iterate over the fruits in fruit_list
    for fruit in fruit_list:
        print fruit

As we saw with items we can unpack tuples into multiple values:

x, y = (1, 2)
print x
print y
# 1
# 2

So we can unpack each fruit into its component parts:

for fruit_name, fruit_list in fruit_stand.items():
    # Ignore fruit_name and iterate over the fruits in fruit_list
    for color, quantity, cost in fruit_list:
        print color, quantity, cost

And then getting the total isn't hard:

# We need to store our value somewhere
total_value = 0
for fruit_name, fruit_list in fruit_stand.items():
    # Ignore fruit_name and iterate over the fruits in fruit_list
    for color, quantity, cost in fruit_list:
        total_value += (quantity * cost)

print total_value

All that being said, there are much clearer ways of doing things:

  1. You could use list comprehension to simplify your for loops:

    for fruit_name in fruit_stand
        operation(fruit_name)
    

    can be translated to this list comprehension:

    [operation(fruit_name) for fruit_name in fruit_stand]
    

    Therefore, we can translate our nested for loops into:

    sum([cost * quantity \  # Final operation goes in front
        for _, fruits in fruit_stand.items() \
            for _, cost, quantity in fruits])
    

    Because we don't actually need the list we can get rid of it and Python will create a generator for us instead:

    sum(cost * quantity \  # Note the missing []
        for _, fruits in fruit_stand.items() \
            for _, cost, quantity in fruits)
    
  2. You could add a __add__ method to Fruit so that adding two sets of fruits together gives you the total cost of both sets of Fruit (but you would probably want to create an intermediate data structure to do that, say Basket so Fruit didn't have to worry about quantity which doesn't really belong to Fruit, save in the sense that any instance of Fruit has the intrinsic quantity 1. I'm omitting the code for this option because this answer is already far too long.

like image 138
Sean Vieira Avatar answered Dec 22 '22 18:12

Sean Vieira


The word you're looking for is "tuple". These "parentheticals" are tuples.

One of Python's major strengths is its compact syntax for iterating over lists. You can calculate the sum of the prices of each fruit in a single line:

>>> fruit = [("Red", 10, 0.99), ("Green", 9, 0.69)]
>>> sum(qty * price for color, qty, price in fruit)
16.11

Breaking it down, the stuff inside of sum() is called a generator expression. for color, qty, price in fruit iterates over fruit and unpacks the tuples into three named variables. These variables can then be used on the left-hand side of the for. For each tuple in the fruit list, the generator expression calculates qty * price.

If you put this expression inside of square brackets it becomes a list comprehension and lets you see the calculated values.

>>> [qty * price for color, qty, price in fruit]
[9.9, 6.209999999999999]
like image 29
John Kugelman Avatar answered Dec 22 '22 19:12

John Kugelman