How to remove dict keys if value is empty - python

In my form post request I'm grabbing all form info, but it seems as though there are some empty keys and values. I'd like to remove all instances of empty keys and values. This what I have so far, and it's obviously not working.
post_dict = dict(request.POST)
item_data = {}
for key, value in post_dict.items():
if value is None:
del post_dict[key]
field = key.split('[')[1].replace(']', '')
item_data[field] = ''.join(value)
print(item_data)
What the print item_data looks like:
{'': '', 'username': 'johndoe', 'email': 'johndoe#gmail.com', ...
If you delete the key, will it delete its respective value? How can I get rid of empty keys and values?

Try this:
new_item_data={k:item_data[k] for k in item_data if item_data[k]}
Any keys that do not have values will be removed.

Maybe you can do what you want using one of these:
dict_1 = {'': '', 'username': 'johndoe', 'email':'', }
dict_2 = dict(x for x in dict_1.iteritems() if any(x))
print dict_2 # {'username': 'johndoe', 'email': ''}
dict_3 = dict(x for x in dict_1.iteritems() if all(x))
print dict_3 # {'username': 'johndoe'}

for key, value in post_dict.items():
In your code you are iterating on post_dict.
However, in the line del post_dict[key] you are modifying the iterator, so it will provide an inconsistent view of the dictionary to for. It is not good to add or delete keys to the dictionary that you are iterating on.
This may give the result you wanted
post_dict = dict(request.POST)
item_data = {}
for key, value in post_dict.items():
if value == "":
continue
if key == "":
continue
field = key.split('[')[1].replace(']', '')
item_data[field] = ''.join(value)
print(item_data)

Try this,
post_dict = {'': '', 'item_data[username]': ['johndoe'], 'item_data[email]': ['johndoe#gmail.com'], 'item_data[campus]': ['madison']}
item_data = {}
for key, value in post_dict.items():
strlist = key.split('[')
if len(strlist) == 1:
continue
new_key = strlist[1].replace(']', '')
new_value = ''.join(value)
# add to the dict if both new_key and new_value are non-empty
if all([new_key, new_value]):
item_data[new_key] = new_value
print(item_data)
# Output
{'username': 'johndoe', 'campus': 'madison', 'email': 'johndoe#gmail.com'}
Previous answer: Delete those items from a dict whose key or value is empty.
d = {'': '', 'username': 'johndoe', 'email': 'johndoe#gmail.com'}
for k, v in d.items():
if not any([k, v]):
del d[k]
print(d)
{'username': 'johndoe', 'email': 'johndoe#gmail.com'}

Related

How edit python dict in example?

I have a dict:
my_dict = {'some.key' : 'value'}
and i want to change it like this:
result = {'some' : {'key' : 'value'}}
how i can do this?
I need to this to create nested classes using dicts:
example:
my_dict = {'nested.key' : 'value'}
class Nested:
key : str
class MyDict:
nested : Nested
if you need this for real use, and not as a coding exercise, you can install extradict and use extradict.NestedData:
In [1]: from extradict import NestedData
In [2]: a = NestedData({'some.key' : 'value'})
In [3]: a["some"]
Out[3]: {'key': <str>}
In [4]: a["some"]["key"]
Out[4]: 'value'
In [5]: a.data
Out[5]: {'some': {'key': 'value'}}
(disclaimer: I am the package author)
Not quite sure if I understand your question, but would
result = {key.split('.')[0]: {key.split('.')[1]: value} for key, value in my_dict.items()}
do the trick?
I hope this function will help you
def foo(obj):
result = {}
for k, v in obj.items():
keys = k.split('.')
caret = result
for i in range(len(keys)):
curr_key = keys[i]
if i == len(keys) - 1:
caret[curr_key] = v
else:
caret.setdefault(curr_key, {})
caret = caret[curr_key]
return result
with recurtion it could look like this (having all keys unique is essential):
my_dict = {'key0' : 'value0',
'nested.key' : 'value',
'nested1.nested1.key1' : 'value1',
'nested2.nested2.nested2.key2' : 'value2'}
def func(k,v):
if not '.' in k: return {k:v}
k1,k = k.split('.',1)
return {k1:func(k,v)}
res = {}
for k,v in my_dict.items():
res.update(func(k,v))
>>> res
'''
{'key0': 'value0',
'nested': {'key': 'value'},
'nested1': {'nested1': {'key1': 'value1'}},
'nested2': {'nested2': {'nested2': {'key2': 'value2'}}}}

Expect alternate solution to update the Dictionary with given reference dictionary

I am trying to update the dictionary "menu" values by getting a value from an appropriate dictionary. I try the following code and get the desired result. But I expect some other alternate ways and a more generic solution in a pythonic way.
Code
language = {"english" : {"lbl01":"File" ,"lbl02":"Accounts"},
"tamil" : {"lbl01":"கோப்பு" ,"lbl02":"கணக்கியல்"},
"hindi" : {"lbl01":"Hindi_File","lbl02":"Hindi_accounts"}}
scut = {"user1": {"lbl01":"Alt+F","lbl02":"F5"},
"user2": {"lbl01":"Ctrl+F","lbl02":"Shift+F5"}}
menu = {"lbl01" :{"id":"file" ,"lan1":"","lan2":"","scut":""},
"lbl02" :{"id":"accounts","lan1":"","lan2":"","scut":""}}
user = ["user2"]
selected_lan = ["tamil","hindi"]
menukey_lst,submenukey_lst =[],[]
for menukey,menuvalue in menu.items():
if menukey not in menukey_lst: menukey_lst.append(menukey)
for submenukey,submenuvalue in menuvalue.items():
if submenukey not in submenukey_lst: submenukey_lst.append(submenukey)
for index,mk in enumerate(menu.keys()):
for item in submenukey_lst:
menu[menukey_lst[index]]["lan1"] = language[selected_lan[0]][menukey_lst[index]]
menu[menukey_lst[index]]["lan2"] = language[selected_lan[1]][menukey_lst[index]]
menu[menukey_lst[index]]["scut"] = (scut[user[0]][mk])
print(menu)
Output
{'lbl01': {'id': 'file', 'lan1': 'கோப்பு', 'lan2': 'Hindi_File', 'scut': 'Ctrl+F'}, `'lbl02': {'id': 'accounts', 'lan1': 'கணக்கியல்', 'lan2': 'Hindi_accounts', 'scut': 'Shift+F5'}}`
This should work.
for key, value in menu.items():
for sub_key in value.keys():
if sub_key == 'lan1':
value[sub_key] = language[selected_lan[0]][key]
elif sub_key == 'lan2':
value[sub_key] = language[selected_lan[1]][key]
elif sub_key == 'scut':
value[sub_key] = scut[user[0]][key]

Dot notation to Json in python

I receive data from the Loggly service in dot notation, but to put data back in, it must be in JSON.
Hence, I need to convert:
{'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}
Into:
{'message': {'code': {'response': 80}, 'status': {'time': 50}}, 'time': 100}
I have put together a function to do so, but I wonder if there is a more direct and simpler way to accomplish the same result.
def dot_to_json(a):
# Create root for JSON tree structure
resp = {}
for k,v in a.items():
# eliminate json. (if metric comes from another type, it will keep its root)
k = re.sub(r'\bjson.\b','',k)
if '.' in k:
# Field has a dot
r = resp
s = ''
k2 = k.split('.')
l = len(k2)
count = 0
t = {}
for f in k2:
count += 1
if f not in resp.keys():
r[f]={}
r = r[f]
if count < l:
s += "['" + f + "']"
else:
s = "resp%s" % s
t = eval(s)
# Assign value to the last branch
t[f] = v
else:
r2 = resp
if k not in resp.keys():
r2[k] = {}
r2[k] = v
return resp
You can turn the path into dictionary access with:
def dot_to_json(a):
output = {}
for key, value in a.iteritems():
path = key.split('.')
if path[0] == 'json':
path = path[1:]
target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
target[path[-1]] = value
return output
This takes the key as a path, ignoring the first json part. With reduce() you can walk the elements of path (except for the last one) and fetch the nested dictionary with it.
Essentially you start at output and for each element in path fetch the value and use that value as the input for the next iteration. Here dict.setdefault() is used to default to a new empty dictionary each time a key doesn't yet exist. For a path ['foo', 'bar', 'baz'] this comes down to the call output.setdefault('foo', {}).setdefault('bar', {}).setdefault('baz', {}), only more compact and supporting arbitrary length paths.
The innermost dictionary is then used to set the value with the last element of the path as the key.
Demo:
>>> def dot_to_json(a):
... output = {}
... for key, value in a.iteritems():
... path = key.split('.')[1:] # ignore the json. prefix
... target = reduce(lambda d, k: d.setdefault(k, {}), path[:-1], output)
... target[path[-1]] = value
... return output
...
>>> dot_to_json({'json.message.status.time':50, 'json.message.code.response':80, 'json.time':100}))
{'message': {'status': {'time': 50}, 'code': {'response': 80}}, 'time': 100}

python generating nested dictionary key error

I am trying to create a nested dictionary from a mysql query but I am getting a key error
result = {}
for i, q in enumerate(query):
result['data'][i]['firstName'] = q.first_name
result['data'][i]['lastName'] = q.last_name
result['data'][i]['email'] = q.email
error
KeyError: 'data'
desired result
result = {
'data': {
0: {'firstName': ''...}
1: {'firstName': ''...}
2: {'firstName': ''...}
}
}
You wanted to create a nested dictionary
result = {} will create an assignment for a flat dictionary, whose items can have any values like "string", "int", "list" or "dict"
For this flat assignment
python knows what to do for result["first"]
If you want "first" also to be another dictionary you need to tell Python by an assingment
result['first'] = {}.
otherwise, Python raises "KeyError"
I think you are looking for this :)
>>> from collections import defaultdict
>>> mydict = lambda: defaultdict(mydict)
>>> result = mydict()
>>> result['Python']['rules']['the world'] = "Yes I Agree"
>>> result['Python']['rules']['the world']
'Yes I Agree'
result = {}
result['data'] = {}
for i, q in enumerate(query):
result['data']['i'] = {}
result['data'][i]['firstName'] = q.first_name
result['data'][i]['lastName'] = q.last_name
result['data'][i]['email'] = q.email
Alternatively, you can use you own class which adds the extra dicts automatically
class AutoDict(dict):
def __missing__(self, k):
self[k] = AutoDict()
return self[k]
result = AutoDict()
for i, q in enumerate(query):
result['data'][i]['firstName'] = q.first_name
result['data'][i]['lastName'] = q.last_name
result['data'][i]['email'] = q.email
result['data'] does exist. So you cannot add data to it.
Try this out at the start:
result = {'data': []};
You have to create the key data first:
result = {}
result['data'] = {}
for i, q in enumerate(query):
result['data'][i] = {}
result['data'][i]['firstName'] = q.first_name
result['data'][i]['lastName'] = q.last_name
result['data'][i]['email'] = q.email

Store path to dictionary value for setting value

Consider a dict that holds a person:
person = {}
person['name'] = 'Jeff Atwood'
person['address'] = {}
person['address']['street'] = 'Main Street'
person['address']['zip'] = '12345'
person['address']['city'] = 'Miami'
How might the path to a location in the dictionary be stored for writing to the value?
# Set city (Existing field)
city_field = ['address', 'city']
person[city_field] = 'London' // Obviously won't work!
# Set country (New field)
country_field = ['address', 'country']
person[city_country] = 'UK' // Obviously won't work!
Note that I had previously asked how to store the path to dictionary value for reading.
Use tuples as index.
city_field = ('address', 'city')
country_field = ('address', 'country')
Usage:
>>> person = {}
>>> city_field = ('address', 'city')
>>> country_field = ('address', 'country')
>>> person[city_field] = 'Miami'
>>> person[country_field] = 'UK'
>>> person
{('address', 'country'): 'UK', ('address', 'city'): 'Miami'}
Got it! Actually my co-worker Moshe is the brains behind this one:
def set_path(someDict, path, value):
for x in path[::-1]:
value = {x: value}
return deepupdate(someDict, value)
def deepupdate(original, update):
for key, value in original.items():
if not key in update:
update[key] = value
elif isinstance(value, dict):
deepupdate(value, update[key])
return update
person = {}
person = set_path(person, ['name'], 'Shalom')
person = set_path(person, ['address', 'city'], 'Toronto')
person = set_path(person, ['address', 'street'], 'Baddessa')
pprint(person)
Returns:
{
'address': {
'city': 'Toronto',
'street': 'Baddessa'
},
'name': 'Shalom'
}
This depends on user Stanislav's excellent recursive dictionary deepmerge() function.

Categories