1

I have the following list

count = 3.5, price = 2500

count = 3, price = 400

count = 2, price = 3000

count = 3.5, price = 750

count = 2, price = 500

I want to find the average price for all where the count is the same. For example:

count = 2, price = 3000

count = 2, price = 500

3000 + 500 = 3500

3500/2 = 1750

Avg for 'count 2' is 1750

Here's my code so far

avg_list = [value["average"] for value in dictionary_database_list] 

counter_obj = collections.Counter(count_list)

print ("AVG:")

for i in counter_obj:

    print (i, counter_obj[i])
Prasad
  • 1,562
  • 5
  • 26
  • 40
  • The "dictionary" tag looks like a good start--what have you tried so far? – KernelPanic Feb 18 '17 at 01:05
  • 2
    simple to code! think little harder you will do it!! :) – phunsukwangdu Feb 18 '17 at 01:05
  • 1
    If only there was a function that could **group** the items **by** a shared key! Oh, wait, [there is!](https://docs.python.org/3/library/itertools.html?highlight=groupby#itertools.groupby) – aghast Feb 18 '17 at 01:08
  • I'm able to get the count for an object. So I was able to add up how many times count = 2 showed up. But I don't know how to compare that back to the price value. Here's what I have – user7583486 Feb 18 '17 at 01:11
  • avg_list = [value["average"] for value in dictionary_database_list] counter_obj = collections.Counter(count_list) print ("AVG:") for i in counter_obj: print (i, counter_obj[i]) – user7583486 Feb 18 '17 at 01:12
  • @AustinHastings `groupby` would require sorting the data, then grouping it, then calculating the average for each group (actually [a bit inconvenient](http://stackoverflow.com/q/4963784/7484636) since `groupby` returns generators). It's a valid method, but a bit roundabout. – KernelPanic Feb 18 '17 at 04:10
  • 1
    @KernelPanic True. But that boils down to "sorting the data", since grouping it is what groupby *does*, and computing the average is going to have to happen anyway. (And calling `statistics.mean()` isn't really that hard, is it?) – aghast Feb 18 '17 at 20:32
  • @AustinHastings also true :) fwiw I would probably pick your way if I were determined to get everything into 1 dict/list comprehension, which I often am – KernelPanic Feb 18 '17 at 20:52

2 Answers2

1

I'll admit I'm not 100% clear on what you're looking for here, but I'll give it a shot:

A good strategy when you want to iterate over a list of "things" and accumulate some kind of information about "the same kind of thing" is to use a hash table. In Python, we usually use a dict for algorithms that require a hash table.

To collect enough information to get the average price for each item in your list, we need:

a) the total number of items with a specific "count"

b) the total price of items with a specific "count"

So let's build a data structure that maps a "count" to a dict containing "total items" and "total price" for the item with that "count".

Let's take our input in the format:

item_list = [
    {'count': 3.5, 'price': 2500},
    {'count': 3, 'price': 400},
    {'count': 2, 'price': 3000},
    {'count': 3.5, 'price': 750},
    {'count': 2, 'price': 500},
]

Now let's map the info about "total items" and "total price" in a dict called items_by_count:

for item in item_list:
    count, price = item['count'], item['price']
    items_by_count[count]['total_items'] += 1
    items_by_count[count]['total_price'] += price

But wait! items_by_count[count] will throw a KeyError if count isn't already in the dict. This is a good use case for defaultdict. Let's define the default value of a count we've never seen before as 0 total price, and 0 total items:

from collections import defaultdict
items_by_count = defaultdict(lambda: {
    'total_items': 0,
    'total_price': 0
})

Now our code won't throw an exception every time we see a new value for count.

Finally, we need to actually take the average. Let's get the information we need in another dict, mapping count to average price. This is a good use case for a dict comprehension:

{count: item['total_price'] / item['total_items']
for count, item in items_by_count.iteritems()}

This iterates over the items_by_count dict and creates the new dict that we want.

Putting it all together:

from collections import defaultdict

def get_average_price(item_list):
    items_by_count = defaultdict(lambda: {
        'total_items': 0,
        'total_price': 0
    })

    for item in item_list:
        count, price = item['count'], item['price']
        items_by_count[count]['total_items'] += 1
        items_by_count[count]['total_price'] += price

    return {count: item['total_price'] / item['total_items']
            for count, item in items_by_count.iteritems()}

If we pass in our example input dict, this function returns: {3.5: 1625, 2: 1750, 3: 400}

Which is hopefully the output you want! Be cautious of gotchas like float division in your particular Python version.

Community
  • 1
  • 1
KernelPanic
  • 600
  • 8
  • 19
-2

You need to iterate over your items

See documentation

  • avg(dictionary.values()) is probably what you want
1w3j
  • 566
  • 8
  • 24
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. - [From Review](/review/low-quality-posts/15253408) – Brandon Anzaldi Feb 18 '17 at 01:37
  • I though I could help just posting a single method since @phunsukwangdu comment, and then upvoted for me too. 'simple code'. PD:I posted a permalink from python official documentation. Changes could happen but deletion of a so common method...idts – 1w3j Feb 18 '17 at 01:57
  • I'm still pretty lost with this one... Not sure how to implement avg(dictionary.values()) – user7583486 Feb 18 '17 at 02:28