Python Dictionary Additions
Question:
I’m a little new to Python and have been able to build a pretty nice application over here, but I’ve been spinning my wheels for a few hours here and I wanted to ask for a little help. Here’s my loop where I’m adding to a dictionary:
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
else:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']],{
'user_id': toast['user_id'],
'username': toast['username']
}
In my case, I currently have a total of three toasts for two different checkins. The above loop gives me this dictionary:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: {'user_id': 1, 'username': 'shaunwo'}}
And then when I try to use it in my jinja form, it works as I would expect for checkin 8 with the two toasts, but it does not work for my checkin 9 that only has one toast. I found that if I manually tweak that dictionary a bit to this:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: ({'user_id': 1, 'username': 'shaunwo'},)}
THAT works in my jinja form beautifully. But I don’t know how to revise my for loop above accordingly to give me that kind of dictionary with the (,) around the single instance for checkin 9.
Answers:
You can use the dict.setdefault
method to initialize a non-existent key of a dict with a list so that it can be consistently appended with the desired sub-dict:
for toast in checkin_toasts:
toasts.setdefault(toast['checkin_id'], []).append({
'user_id': toast['user_id'],
'username': toast['username']
})
The problem is that in one branch of the if
statement, you set toasts[toast['checkin_id']]
to a dictionary, while in the other you set it to a tuple of its previous value and a dictionary:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
vs.
toasts[toast['checkin_id']] = (
toasts[toast['checkin_id']],
{
'user_id': toast['user_id'],
'username': toast['username']
},
)
Meanwhile, your frontend is expecting a tuple (or list) of dictionaries, regardless of whether there’s 1, 2 or more.
As @blhsing posted, you can achieve this by always making it a list and appending entries to it; that’s probably the neatest solution.
However, to answer the question as asked, to make a tuple of one item, there’s special syntax for that in Python; a trailing comma:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
},
If you prefer to make it more explicit, you can add parentheses:
toasts[toast['checkin_id']] = ({
'user_id': toast['user_id'],
'username': toast['username']
},)``
At that point, you’d also need to fix the other case to make a longer tuple rather than nesting it:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']] + ({
'user_id': toast['user_id'],
'username': toast['username']
},)
As in @blhsing’s answer, you can also combine those two into one, using the .get()
method with a default to give you an empty tuple when adding the first toast:
toasts[toast['checkin_id']] = toasts.get(toast['checkin_id'], ()) + ({
'user_id': toast['user_id'],
'username': toast['username']
},)
It seems that you are aggregating the toasts into a tuple
if they have the same checkin_id
and return a dictionary with checkin_id
s as keys and toast tuples as values.
In this case, you could use collections.defaultdict
and aggregate the toasts with the same checkin_id
with a tuple
.
from collections import defaultdict
toasts = defaultdict(tuple)
for toast in checkin_toasts:
toasts[toast['checkin_id']] += ({
'user_id': toast['user_id'],
'username': toast['username']
}, )
Otherwise, you could recreate the tuple every time by yourself without the help of collections.defaultdict
.
This key point is to use the asterisk operator *
to unpack the existing tuple and append the new element for the tuple assignment.
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
# Always create a new key with an empty tuple as its value if the key does not exist.
toasts[toast['checkin_id']] = tuple()
toasts[toast['checkin_id']] = *toasts[toast['checkin_id']], {
'user_id': toast['user_id'],
'username': toast['username']
}
# # Equals to
# toasts[toast['checkin_id']] = tuple(*toasts[toast['checkin_id']], {
# 'user_id': toast['user_id'],
# 'username': toast['username']
# })
I would suggest the first approach.
Thank you SO MUCH!! I’m back in business. Thank you for the insights.
I’m a little new to Python and have been able to build a pretty nice application over here, but I’ve been spinning my wheels for a few hours here and I wanted to ask for a little help. Here’s my loop where I’m adding to a dictionary:
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
else:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']],{
'user_id': toast['user_id'],
'username': toast['username']
}
In my case, I currently have a total of three toasts for two different checkins. The above loop gives me this dictionary:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: {'user_id': 1, 'username': 'shaunwo'}}
And then when I try to use it in my jinja form, it works as I would expect for checkin 8 with the two toasts, but it does not work for my checkin 9 that only has one toast. I found that if I manually tweak that dictionary a bit to this:
{8: ({'user_id': 1, 'username': 'shaunwo'}, {'user_id': 2, 'username': 'shaunwo2'}), 9: ({'user_id': 1, 'username': 'shaunwo'},)}
THAT works in my jinja form beautifully. But I don’t know how to revise my for loop above accordingly to give me that kind of dictionary with the (,) around the single instance for checkin 9.
You can use the dict.setdefault
method to initialize a non-existent key of a dict with a list so that it can be consistently appended with the desired sub-dict:
for toast in checkin_toasts:
toasts.setdefault(toast['checkin_id'], []).append({
'user_id': toast['user_id'],
'username': toast['username']
})
The problem is that in one branch of the if
statement, you set toasts[toast['checkin_id']]
to a dictionary, while in the other you set it to a tuple of its previous value and a dictionary:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
}
vs.
toasts[toast['checkin_id']] = (
toasts[toast['checkin_id']],
{
'user_id': toast['user_id'],
'username': toast['username']
},
)
Meanwhile, your frontend is expecting a tuple (or list) of dictionaries, regardless of whether there’s 1, 2 or more.
As @blhsing posted, you can achieve this by always making it a list and appending entries to it; that’s probably the neatest solution.
However, to answer the question as asked, to make a tuple of one item, there’s special syntax for that in Python; a trailing comma:
toasts[toast['checkin_id']] = {
'user_id': toast['user_id'],
'username': toast['username']
},
If you prefer to make it more explicit, you can add parentheses:
toasts[toast['checkin_id']] = ({
'user_id': toast['user_id'],
'username': toast['username']
},)``
At that point, you’d also need to fix the other case to make a longer tuple rather than nesting it:
toasts[toast['checkin_id']] = toasts[toast['checkin_id']] + ({
'user_id': toast['user_id'],
'username': toast['username']
},)
As in @blhsing’s answer, you can also combine those two into one, using the .get()
method with a default to give you an empty tuple when adding the first toast:
toasts[toast['checkin_id']] = toasts.get(toast['checkin_id'], ()) + ({
'user_id': toast['user_id'],
'username': toast['username']
},)
It seems that you are aggregating the toasts into a tuple
if they have the same checkin_id
and return a dictionary with checkin_id
s as keys and toast tuples as values.
In this case, you could use collections.defaultdict
and aggregate the toasts with the same checkin_id
with a tuple
.
from collections import defaultdict
toasts = defaultdict(tuple)
for toast in checkin_toasts:
toasts[toast['checkin_id']] += ({
'user_id': toast['user_id'],
'username': toast['username']
}, )
Otherwise, you could recreate the tuple every time by yourself without the help of collections.defaultdict
.
This key point is to use the asterisk operator *
to unpack the existing tuple and append the new element for the tuple assignment.
for toast in checkin_toasts:
if toast['checkin_id'] not in toasts:
# Always create a new key with an empty tuple as its value if the key does not exist.
toasts[toast['checkin_id']] = tuple()
toasts[toast['checkin_id']] = *toasts[toast['checkin_id']], {
'user_id': toast['user_id'],
'username': toast['username']
}
# # Equals to
# toasts[toast['checkin_id']] = tuple(*toasts[toast['checkin_id']], {
# 'user_id': toast['user_id'],
# 'username': toast['username']
# })
I would suggest the first approach.
Thank you SO MUCH!! I’m back in business. Thank you for the insights.