6

I have the following dictionary

dict1 ={"city":"","name":"yass","region":"","zipcode":"",
       "phone":"","address":"","tehsil":"", "planet":"mars"}

I am trying to create a new dictionary that will be based on dict1 but,

  1. it will not contain keys with empty strings.
  2. it will not contain those keys that I dont want to include.

i have been able to fulfill the requirement 2 but getting problem with requirement 1. Here is what my code looks like.

dict1 ={"city":"","name":"yass","region":"","zipcode":"",
   "phone":"","address":"","tehsil":"", "planet":"mars"}

blacklist = set(("planet","tehsil"))    
new = {k:dict1[k] for k in dict1 if k not in blacklist} 

this gives me the dictionary without the keys: "tehsil", "planet" I have also tried the following but it didnt worked.

new = {k:dict1[k] for k in dict1 if k not in blacklist and dict1[k] is not None}

the resulting dict should look like the one below:

new = {"name":"yass"}
jamylak
  • 128,818
  • 30
  • 231
  • 230
hjelpmig
  • 1,406
  • 6
  • 19
  • 23

5 Answers5

5

This is a white list version:

>>> dict1 ={"city":"","name":"yass","region":"","zipcode":"",
       "phone":"","address":"","tehsil":"", "planet":"mars"}
>>> whitelist = ["city","name","planet"]
>>> dict2 = dict( (k,v) for k, v in dict1.items() if v and k in whitelist )
>>> dict2
{'planet': 'mars', 'name': 'yass'}

Blacklist version:

>>> blacklist = set(("planet","tehsil"))
>>> dict2 = dict( (k,v) for k, v in dict1.items() if v and k not in blacklist )
>>> dict2
{'name': 'yass'}

Both are essentially the same expect one has not in the other in. If you version of python supports it you can do:

>>> dict2 = {k: v for k, v in dict1.items() if v and k in whitelist}

and

>>> dict2 = {k: v for k, v in dict1.items() if v and k not in blacklist}
jamylak
  • 128,818
  • 30
  • 231
  • 230
HennyH
  • 7,794
  • 2
  • 29
  • 39
  • may as well use a dictionary comprehension `{k: v for k, v ....}`, even though it's not Python 2.6 compatible like this, we know OP is using 2.7+ – jamylak May 22 '13 at 14:07
4

This would have to be the fastest way to do it (using set difference):

>>> dict1 = {"city":"","name":"yass","region":"","zipcode":"",
       "phone":"","address":"","tehsil":"", "planet":"mars"}
>>> blacklist = {"planet","tehsil"}
>>> {k: dict1[k] for k in dict1.viewkeys() - blacklist if dict1[k]}
{'name': 'yass'}

White list version (using set intersection):

>>> whitelist = {'city', 'name', 'region', 'zipcode', 'phone', 'address'}
>>> {k: dict1[k] for k in dict1.viewkeys() & whitelist if dict1[k]}
{'name': 'yass'}
jamylak
  • 128,818
  • 30
  • 231
  • 230
  • Thanks for that. what will be the solution if I only want non empty white list values? – hjelpmig May 22 '13 at 14:14
  • @yasra002 added that as well – jamylak May 22 '13 at 14:17
  • Which option is better using sets that I used or the one one that you used. I am pretty new to python so I am not sure which one is the best one. – hjelpmig May 22 '13 at 14:21
  • 1
    @yasra002 People only wrote sets like `set((1, 2, 3))` back in Python <= 2.6 when there **was no** set literal(`{1, 2, 3}`). What you are doing is creating a `tuple` and passing it to a `set` constructor. Nowadays we have set literals so you should use them ;) – jamylak May 22 '13 at 14:22
1

You're on the right track. Consider:

Python 2.7.3 (default, Apr 24 2012, 00:00:54) 
[GCC 4.7.0 20120414 (prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> dict1 ={"city":"","name":"yass","region":"","zipcode":"",
...    "phone":"","address":"","tehsil":"", "planet":"mars"}
>>> 
>>> def isgood(undesired, key, val): return key not in undesired and key and val
... 
>>> dict([x for x in dict1.items() if isgood(["planet", "tehsil"], *x)])
{'name': 'yass'}
Ishpeck
  • 2,001
  • 1
  • 19
  • 21
1

Simply test dict1[k] for Truth value (instead of is None.).

new = {k:dict1[k] for k in dict1 if k not in blacklist and dict1[k]}
Velimir Mlaker
  • 10,664
  • 4
  • 46
  • 58
1

Testing if the value is not an empty string is not done using is not None.

An empty string evaluates as False, while any non-empty string evaluates as True. Hence, you can test it directly, and simply remove the is not None from your expression :

new = {k:dict1[k] for k in dict1 if k not in blacklist and dict1[k]}
njzk2
  • 38,969
  • 7
  • 69
  • 107