How to iterate over two dictionaries at once and get a result using values and keys from both

Question:

def GetSale():#calculates expected sale value and returns info on the stock with              highest expected sale value
      global Prices
      global Exposure
      global cprice
      global bprice
      global risk
      global shares
      global current_highest_sale
      best_stock=' '
      for value in Prices.values():
          cprice=value[1]
          bprice=value[0]
          for keys, values in Exposure.items():
             risk=values[0]
             shares=values[1]
             Expected_sale_value=( (cprice - bprice ) - risk * cprice) * shares
             print (Expected_sale_value)
             if current_highest_sale < Expected_sale_value:
                current_highest_sale=Expected_sale_value
                best_stock=Exposure[keys]
     return best_stock +" has the highest expected sale value"

Above is my code currently. For some reason though, it appears to be doing the first loop, then the second, then the second, then the first, then the second. It appears to do the second loop each time it gets to it before going back to the first for loop. It is because of this that the answers I’m getting are not correct.

Asked By: arisonu123

||

Answers:

The question is a bit vague, but answering the title, you can get both keys and values at the same time like this:

>>> d = {'a':5, 'b':6, 'c': 3}
>>> d2 = {'a':6, 'b':7, 'c': 3}
>>> for (k,v), (k2,v2) in zip(d.items(), d2.items()):
    print k, v
    print k2, v2


a 5
a 6
c 3
c 3
b 6
b 7

However, do mind that keys in dictionaries aren’t ordered. Furthermore, if the two dictionaries do not contain the same number of keys, the code above will fail.

Answered By: aIKid

Looking at your problem, I would suggest you to create generator expression that navigates the two dictionary in pairs and using max with a custom key to calculate sale price to evaluate expected_sale_price and the corresponding stock

Sample Data

Prices = dict(zip(range(10), ((randint(1,100), randint(1,100)) for _ in range(10))))
Exposure = dict(zip(range(10), ((randint(1,100), randint(1,100)) for _ in range(10))))

Sample Code

def GetSale(Prices, Exposure):
    '''Get Sale does not need any globals if you pass the necessary variables as
       parameteres
    '''
    from itertools import izip
    def sale_price(args):
        '''
        Custom Key, used with the max function
        '''
        key, (bprice, cprice), (risk, shares) = args
        return ( (cprice - bprice ) - risk * cprice) * shares

    #Generator Function to traverse the dict in pairs
    #Each item is of the format (key, (bprice, cprice), (risk, shares))
    Price_Exposure = izip(Prices.keys(), Prices.values(), Exposure.values())


    #Expected sale price using `max` with custom key
    expected_sale_price = max(Price_Exposure, key = sale_price)
    key, (bprice, cprice), (risk, shares) =  expected_sale_price
    #The best stock is the key in the expected_sale_Price
    return "Stock {} with values bprice={}, cprice = {}, risk={} and shares={} has the highest expected sale value".format(key, bprice, cprice, risk, shares)
Answered By: Abhijit

The question isn’t well defined, and the answer accepted will fail for some dictionaries. It relies on key ordering, which isn’t guaranteed. Adding additional keys to a dictionary, removing keys, or even the order they are added can affect the ordering.

A safer solution is to choose one dictionary, d in this case, to get the keys from, then use those to access the second dictionary:

d = {'a':5, 'b':6, 'c': 3}
d2 = {'a':6, 'b':7, 'c': 3}
[(k, d2[k], v) for k, v in d.items()]

Result:

[('b', 7, 6), ('a', 6, 5), ('c', 3, 3)]

This isn’t more complex than the other answers, and is explicit about which keys are being accessed. If the dictionaries have different key orderings, say d2 = {'x': 3, 'b':7, 'c': 3, 'a':9}, consistent results are still given.

Answered By: user2699
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.