How do I aggregate 5 random samples of a dict?

Question:

I’m trying to sample 5 items from a dict then aggregate them by sum.
In this case by building a sum of all 5 prices.
How do I do that?

import random

mydict = {
    1: {"name":"item1","price": 16}, 
    2: {"name":"item2","price": 14},
    3: {"name":"item3","price": 16}, 
    4: {"name":"item4","price": 14}, 
    5: {"name":"item5","price": 13},
    6: {"name":"item6","price": 16},
    7: {"name":"item7","price": 11}, 
    8: {"name":"item8","price": 12}, 
    9: {"name":"item9","price": 14},
    10: {"name":"item10","price": 14},
}

randomlist = random.sample(mydict.items(), 5)
print(sum(randomlist)) # This line needs to work properly.
Asked By: NIPPE

||

Answers:

Random dicts

To get random dicts you can do it this way.

randomlist = random.sample(list(mydict.items()), 5)
dict(randomlist)

Result:

{10: {'name': 'item10', 'price': 14},
 8: {'name': 'item8', 'price': 12},
 7: {'name': 'item7', 'price': 11},
 9: {'name': 'item9', 'price': 14},
 5: {'name': 'item5', 'price': 13}}

Get final sum fast

But if you only look for final sum of prices you can do it a bit faster.

randomlist = random.sample(list(mydict.values()), 5)
sum(x['price'] for x in randomlist)

Result:

69.0

V3 the compact one

sum(random.sample([x['price'] for x in mydict.values()], 5))
Answered By: Aidis

You don’t care about the keys 1, 2, 3, just use mydict.values()

Then take you have a list of 5 dict {name:,price:}, takes al the names, and all the prices for the sum

randomlist = random.sample(list(mydict.values()), 5)
print("Prices of", ",".join(item['name'] for item in randomlist))
print(sum(item['price'] for item in randomlist))
Answered By: azro

Just to add to the existing answers, you should consider printing the variables in every step whenever the type of the variable is not clear.

The sum function repeatedly calls the + operator equivalent of a class (the __add__ method).

Here, you have dict of dicts. You have keys 1 to 10 mapping 10 dicts. When you sample a random one from them, you get a tuple as (key, inner_dict) (I did not know this beforehand, I printed it out to find out), which you have to unpack further to get price specifically.

When I do randomlist = random.sample(mydict.items(), 2) and print randomlist, the output is a list of tuple containing key and value like this

[(6, {'name': 'item6', 'price': 16}), (1, {'name': 'item1', 'price': 16})]

Now, this is the implementation for the function sum.
How to implement built-in sum() of the class?

def sum(sequence, start=0):
    for value in sequence:
        start = start + value
    return start

As you can see, it keeps a starting value of zero as default and repeatedly adds the entities in the iterable (outermost one is list here).

So it starts sum = 0 (of type int) and tries to perform 0+(key,dict). Hence, the error TypeError: unsupported operand type(s) for +: 'int' and 'tuple'. If you modify the code to start with an empty tuple instead, it will start adding tuples, since you can add two tuples and get a tuple.

randomlist = random.sample(mydict.items(), 5)
print(mysum(randomlist,start=())) # This line needs to work properly

Now we try to add () and (key,dict) which results in (key,dict) then, (key,dict)+(key1, dict1) and so on which are valid.

Now, if you want to add all prices in the random list, first you have to get all the tuple containing keys and inner dictionaries.

total = 0
for tup in randomlist:
    #now get the dictionary (2nd element from the tuple)
    inner_dict = tup[1]
    #now get price from inner dict
    price = inner_dict['price']
    total += price
print(total)

This is not the fast or pythonic way (they are suggested in other answers), but this is how you have to visualize while handling nested data types. Once you understand this, you can proceed to optimize or beautify the code.

Answered By: Shriraj Hegde