nutship
nutship

Reputation: 4924

Removing nested dict items with dict comprehension

I have two dicts:

blocked = {'-5.00': ['121', '381']}
all_odds = {'-5.00': '{"121":[1.85,1.85],"381":[2.18,1.73],"16":[2.18,1.61],"18":\
            [2.12,1.79]}'}

I want to first check whether the .keys() comparision (==) returns True, here it does (both -5.00) then I want to remove all items from all_odds that has the key listed in blocked.values() .

For the above it should result in:

all_odds_final = {'-5.00': '{"16":[2.18,1.61],"18": [2.12,1.79]}'}

I tried for loop:

if blocked.keys() == all_odds.keys():
    for value in blocked.values():
        for v in value:
            for val in all_odds.values():
                val = eval(val)
                if val.has_key(v):
                    del val[v] 

which you know is very ugly plus it's not working properly yet.

Upvotes: 0

Views: 1274

Answers (3)

rtrwalker
rtrwalker

Reputation: 1021

This seems to work:

blocked = {'-5.00': ['121', '381']}
all_odds = {'-5.00': {"121":[1.85,1.85],"381":[2.18,1.73],"16":[2.18,1.61],"18":\
        [2.12,1.79]}}
all_odds_final = dict(all_odds)
for key, blocks in blocked.iteritems():
    map(all_odds_final[key].pop,blocks,[])

If you do not want to copy the dictionary, you can just pop items out of the original all_odds dictionary:

for key, blocks in blocked.iteritems():
    map(all_odds[key].pop,blocks,[])

The empty list in the map function is so pop gets called with None as it's second argument. Without it pop only gets one argument and will return an error if the key is not present.

Upvotes: 1

Achrome
Achrome

Reputation: 7821

Here's how you can do the same in about 2 lines. I'm not going to use ast, or eval here, but you can add that if you want to use that.

>>> blocked = {'-5.00': ['121', '381']}
>>> all_odds = {'-5.00': {'121':[1.85,1.85],'381':[2.18,1.73],'16':[2.18,1.61],'18':\
...      [2.12,1.79]}}
>>> bkeys = [k for k in all_odds.keys() if k in blocked.keys()]
>>> all_odds_final = {pk: {k:v for k,v in all_odds.get(pk).items() if k not in blocked.get(pk)} for pk in bkeys}
>>> all_odds_final
{'-5.00': {'18': [2.12, 1.79], '16': [2.18, 1.61]}}

Upvotes: 1

TerryA
TerryA

Reputation: 59984

First, make the string a dictionary with ast.literal_eval(). Don't use eval():

>>> import ast
>>> all_odds['-5.00'] = ast.literal_eval(all_odds['-5.00'])

Then you can use a dictionary comprehension:

>>> if blocked.keys() == all_odds.keys():
...     print {blocked.keys()[0] : {k:v for k, v in all_odds.values()[0].iteritems() if k not in blocked.values()[0]}}
... 
{'-5.00': {'18': [2.12, 1.79], '16': [2.18, 1.61]}}

But if you want the value of -5.00 as a string...

>>> {blocked.keys()[0]:str({k: v for k, v in all_odds.values()[0].iteritems() if k not in blocked.values()[0]})}
{'-5.00': "{'18': [2.12, 1.79], '16': [2.18, 1.61]}"}

Upvotes: 1

Related Questions