remove the keys which has blank values - python

how to remove keys in a dict which do not have any value. I have a dict as :
d = {'CB': '', 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'H':''}
I want to remove keys which values are blank. I need output as :
d = {'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102], 'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875]}
how to do this?

Use a dict-comprehension:
>>> {k:v for k, v in d.items() if v != ''}
{'N': [-6.626999855041504, -2.318000078201294, 7.9029998779296875], 'CA': [-7.5269999504089355, -2.2330000400543213, 6.748000144958496], 'C': [-8.081000328063965, -3.619999885559082, 6.406000137329102]}
If by empty you meant any falsy value then use just if v.
If you want to modify the original dict itself(this will affect all the references to the dict object):
for k, v in d.items():
if not v: del d[k]

>> {key:value for key, value in d.items() if value}

If you really need to do this in one-line:
for k in [k for k,v in d.iteritems() if not v]: del d[k]
This is ugly. It makes a list of all of the keys in d that have a "blank" value and then iterates over this list removing the keys from d (to avoid the unsafe removal of items from dictionary during iteration).
I'd suggest that three lines would be more readable:
blanks = [k for k,v in d.iteritems() if not v]
for k in blanks:
del d[k]
If making a fresh dict is acceptable, use a dict comprehension:
d2 = {k:v for k,v in d.iteritems() if not v}

Related

Reduce nested dictionary to "top-key-root-element" dictionary

I would like to derive a dictionary from a nested dictionary with the top keys as keys and the root elements as values. This post is similar to this one, but I would like to end up with a dictionary not with a list of lists.
Example: How to get from this
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'a':{'b':{'c':'3'}}}}
to this?
{'foo': ['1', '2'], 'bar': '3'}
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'c':{'d':'3'}}}
def get_last_value(d):
if isinstance(d, dict):
for k, v in d.items():
return get_last_value(v)
return d
result = {k:get_last_value(v) for k, v in d.items()}
print(result)
result:
{'foo': ['1', '2'], 'bar': '3'}
d = {'foo':{'a':{'b':['1','2']}},
'bar':{'c':{'d':'3'}}}
for key, value, in d.items():
print(key, value.values())

Update dictionary key(s) by drop starts with value from key in Python

I have a dictionary dict:
dict = {'drop_key1': '10001', 'drop_key2':'10002'}
The key(s) in dict startswith drop_, i would like to update dict by dropping drop_ value from key(s):
dict = {'key1': '10001', 'key2':'10002'}
What is the best approach to do it?
something like
d1 = {'drop_key1': '10001', 'drop_key2':'10002'}
d2 = {k[5:]:v for k,v in d1.items()}
print(d2)
output
{'key1': '10001', 'key2': '10002'}
One approach is, for each key value in the dictionary, you can replace the part of the string with the new string value. For instance:
d = {k.replace('drop_', ''): v for k, v in d.items() if k.strip().startswith('drop_')}
or you can define a function, and get the index of the searched string ("drop_"). If the search string index is 0, then remove it. For instance:
def change_key(key, search):
start_idx = key.find(search)
if start_idx == 0:
key = key.replace(search, "")
return key
d = {change_key(k, search="drop_"): v for k, v in d.items()}
Result:
{'key1': '10001', 'key2': '10002'}
Note that if you use a method, then you can guarantee to remove the search string if it is at the beginning of the string. For instance:
d = {' drop_key1': '10001', 'drop_key2': '10002'}
d = {change_key(k, search="drop_"): v for k, v in d.items()}
Result:
{' drop_key1': '10001', 'key2': '10002'}

How to extract the values from the dictionary with condition

My dictionary is below, if the values end with csv or json i need to put in another dictionary of same dictionary:
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Code is below:
d = {}
for k,v in d.items():
for i in v:
if i.split('.')[1] == 'csv' or i.split('.')[1] == 'json':
d[k] = v
My out
{'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
Expected out
{'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}
You never change v, so the dictionary is unchanged. You should build a new list only keeping the wanted values:
for k,v in d.items():
v = [i for i in v if i.split('.')[1] in ('csv', 'json')]
d[k] = v
or even better:
d = {k: [i for i in v if i.split('.')[1] in ('csv', 'json')]
for k,v in d.items()}
You can try to use rfind to find the last . in the file name and to add it the list if it's matching CSV or JSON
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
d[k] = []
for i in v:
if i[i.rfind(".") + 1:] in ('csv', 'json'):
d[k].append(i)
Please test it:
from collections import defaultdict
x = defaultdict(list)
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
for k, v in d.items():
for i in v:
if i.split('.')[-1] in ['csv', 'json']:
x[k].append(i)
print(dict(x))
You can use dict comprehension with list comp on each of the values while filtering with str.endswith.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
new = {k:[i for i in v if i.endswith(('.csv','.json'))] for k,v in d.items()}
# {'a': ['1.json', '1.csv'], 'B': ['2.json', '2.csv']}
A simple solution would be the following, assuming you want to update the existing dictionary
for k, v in d.items():
for i in v:
if i.rsplit('.')[-1] not in {'csv','json'}:
v.remove(i)
You can use split filename and add condition for checking the file type (using list for comparison could be a better option if you want to add more file types).
Combine this with list Comprehension, which provides a concise way to create lists.
d = {'a': ['1.json', '1.html', '1.csv'], 'B': ['2.json', '2.html', '2.csv']}
filtered_d = {key:[item for item in value if item.split('.')[-1] in ['json','csv']] for key, value in d.items()}
you can check documentation here for more detail on list comprehension.

How to remove dictionary key with known value?

Assume python dict:
mydict = {'a': 100, 'b': 200, 'c': 300}
I know one of the values:
value = 200
How to remove the 'b': 200 pair from the dict? I need this:
mydict = {'a': 100, 'c': 300}
Use a dictionary comprehension. Note that (as jonrsharpe has stated) this will create a new dictionary which excludes the key:value pair that you want to remove. If you want to delete it from your original dictionary then please see his answer.
>>> d = {'a': 100, 'b': 200, 'c': 300}
>>> val = 200
# Use d.items() for Python 2.x and d.iteritems() for Python 3.x
>>> d2 = {k:v for k,v in d.items() if v != val}
>>> d2
{'a': 100, 'c': 300}
It sounds like you want:
for key, val in list(mydict.items()):
if val == value:
del mydict[key]
break # unless you want to remove multiple occurences
You'll need to loop over every items(), either with dict comprehension:
new_dict = {k:v for k,v in my_dict.items() if predicate(value)}
Or modifying the existing dictionary:
for k,v in my_dict.items():
if not predicate(v):
del my_dict[k]
The simplest i found:
for key in [k for k,v in mydict.items() if v==200]:
del mydict[key]

How I can get rid of None values in dictionary?

Something like:
for (a,b) in kwargs.iteritems():
if not b : del kwargs[a]
This code raise exception because changing of dictionary when iterating.
I discover only non pretty solution with another dictionary:
res ={}
res.update((a,b) for a,b in kwargs.iteritems() if b is not None)
Thanks
Another way to write it is
res = dict((k,v) for k,v in kwargs.iteritems() if v is not None)
In Python3, this becomes
res = {k:v for k,v in kwargs.items() if v is not None}
You can also use filter:
d = dict(a = 1, b = None, c = 3)
filtered = dict(filter(lambda item: item[1] is not None, d.items()))
print(filtered)
{'a': 1, 'c': 3}
d = {'a': None, 'b': 'myname', 'c': 122}
print dict(filter(lambda x:x[1], d.items()))
{'b': 'myname', 'c': 122}
I like the variation of your second method:
res = dict((a, b) for (a, b) in kwargs.iteritems() if b is not None)
it's Pythonic and I don't think that ugly. A variation of your first is:
for (a, b) in list(kwargs.iteritems()):
if b is None:
del kwargs[a]
If you need to handle nested dicts, then you can leverage a simple recursive approach:
# Python 2
from collections import Mapping
def filter_none(d):
if isinstance(d, Mapping):
return dict((k, filter_none(v)) for k, v, in d.iteritems() if v is not None)
else:
return d
# Python 3
from collections.abc import Mapping
def filter_none(d):
if isinstance(d, Mapping):
return {k: filter_none(v) for k, v in d.items() if v is not None}
else:
return d
To anybody who may interests, here's another way to get rid of None value. Instead of deleting the key, I change the value of None with a placeholder for the same key.
One use case is applying with Spark RDD.map onto null valued JSON.
def filter_null(data, placeholder="[spark]nonexists"):
# Replace all `None` in the dict to the value of `placeholder`
return dict((k, filter_null(v, placeholder) if isinstance(v, dict) else v if v
is not None else placeholder) for k, v in data.iteritems())
Sample output:
>>> filter_null({'a':None,'b':"nul", "c": {'a':None,'b':"nul"}})
{'a': '[spark]nonexists', 'c': {'a': '[spark]nonexists', 'b': 'nul'}, 'b': 'nul'}
For python3, change the iteritems() to items().
The recursive approach to also filter nested lists of dicts in the dictionary:
def filter_none(d):
if isinstance(d, dict):
return {k: filter_none(v) for k, v in d.items() if v is not None}
elif isinstance(d, list):
return [filter_none(v) for v in d]
else:
return d
Sample output:
data = {'a': 'b', 'c': None, 'd':{'e': 'f', 'h': None, 'i':[{'j': 'k', 'l': None}]}}
print(filter_none(data))
>>> {'a': 'b', 'd': {'e': 'f', 'i': [{'j': 'k'}]}}

Categories