Optimize a dictionary key conditional - python

I would like to optimize this piece of code. I'm sure there is a way to write it in a single line:
if 'value' in dictionary:
x = paas_server['support']
else:
x = []

use dictionary get() method as:
x = dictionary.get('support', [])
if support is not a key in the dictionary, it returns second method's argument, here, an empty list.

Related

Dictionary creation code. What is going on here most likely?

I am looking at this code:
DICT_IDS = dict(x.split('::')
for x in object.method()
['ids_comma_separated'].split(','))
DICT_ATTRS = dict(x.split('::')
for x in object.method()
['comma_separated_key_value_pairs'].split(','))
So each constanty will ultimately refer to a dictionary, but what is going on inside the constructors?
Does this occur first:
x.split('::')
for x in object.method()
So x must be a string that is split on the ::? right?
EDIT
Oh....
for x in object.method()
['ids_comma_separated'].split(',')
is executed first. x is probably another dictionary that we key into using ids_comma_separated whose value is a string that needs to be split on the , like "cat,dog, mouse" into a list. So x is going to be a list?
It is just parsing values like this into a dict:
'ids_comma_separated': "somekey::somevalue,anotherkey::anothervalue"
from a method (object.method()) that returns a dictionary:
class object:
def method():
return {
'ids_comma_separated': "somekey::somevalue,anotherkey::anothervalue"
}
DICT_IDS = dict(x.split('::')
for x in object.method()
['ids_comma_separated'].split(','))
DICT_IDS
# {'somekey': 'somevalue', 'anotherkey': 'anothervalue'}
The part inside the dict() is a generator comprehension but the line breaks make it a little hard to see that:
(x.split('::') for x in object.method()['ids_comma_separated'].split(','))
in each iteration x is somekey::somevalue which gets split once again.

How to change specific value of a dictionary with multiple values (tuple) without getting TypeError

I have a function below which searches for a dictionary key match using an inputted function parameter. If a key match is found I want the value at index 1 (the team) to change to the desired team inputted when the function is called:
dict1 = {'Messi' : ('Argentina','Barcelona'), 'Ronaldo' : ('Portugal','Juventus'), 'Robben': ('Netherlands','Bayern')}
def setNewTeam(plyr, newTeam):
for x in dict1:
if plyr == x:
dict1[plyr][1] = newTeam
setNewTeam('Messi', 'Manchester')
When I run this code however, I get:
TypeError: 'tuple' object does not support item assignment
I know this must be because tuples are not mutable but there must be a way of making this work since i'm working with dictionaries, can anyone lend a hand here?
Thank you!
As the error message says, you cannot assign new items to tuples because tuples are immutable objects in python.
my_tup = (1,2,3)
my_tup[0] = 2 # TypeError
What you could do is using a list instead:
dict1 = {'Messi' : ['Argentina','Barcelona'], 'Ronaldo' : ['Portugal','Juventus'], 'Robben': ['Netherlands','Bayern']}
def setNewTeam(plyr, newTeam):
for x in dict1:
if plyr == x:
dict1[plyr][1] = newTeam
setNewTeam('Messi', 'Manchester')
Note how lists are created using [] while tuples use ().
dict1 = {'Messi' : ('Argentina','Barcelona'), 'Ronaldo' : ('Portugal','Juventus'), 'Robben': ('Netherlands','Bayern')}
def setNewTeam(plyr, newTeam):
for x in dict1:
if plyr == x:
dict1[plyr] = (dict1[plyr][0], newTeam)
setNewTeam('Messi', 'Manchester')
Since you want to update values, tuple is not the good data-structure. You should use a list.
If you still want to use a tuple, you can build a brand new tuple with :
dict1[plyr] = (dict1[plyr][0], newTeam)
dict1[plyr][1] = newTeam
Tuples are immutable, but lists are not. You can do something like:
list1 = list(dict1[plyr])
list1[1] = newTeam
dict1[plyr] = tuple(list1)
It will add the newTeam to your desired location, and it will still be a tuple.

Build a List of Tuples from a Dict

I have a list y of keys from a dictionary that is derived from a call to the Google Places API.
I would like to build a list of tuples for each point of interest:
lst = []
for i in range(len(y)):
lst.append((y[i]['name'], y[i]['formatted_address'], y[i]['opening_hours']['open_now'], y[i]['rating']))
This works if the field is in the list and I receive a list of results that look like the one below, which is exactly what I want:
("Friedman's", '1187 Amsterdam Ave, New York, NY 10027, USA', True, 4.2)
However, the script throws an error if a desired field is not in the list y. How can I build a list of tuples that checks whether the desired field is in y before building the tuple?
Here's what I've tried:
for i in range(len(y)):
t = ()
if y[i]['name']:
t = t + lst.append(y[i]['name'])
if y[i]['formatted_address']:
t = t + lst.append(y[i]['formatted_address'])
if y[i]['opening_hours']['open_now']:
t = t + lst.append(y[i]['opening_hours']['open_now'])
if y[i]['rating']:
t = t + lst.append(y[i]['rating'])
lst.append(t)
However, this doesn't work and seems very inelegant. Any suggestions?
This list comprehension uses default values when one of the keys is not present (using dict.get()). I added variables so you can set the desired default values.
default_name = ''
default_address = ''
default_open_now = False
default_rating = 0.0
new_list = [
(
e.get('name', default_name),
e.get('formatted_address', default_address),
e.get('opening_hours', {}).get('open_now', default_open_now),
e.get('rating', default_rating),
)
for e in y]
For a start, you should almost never loop over range(len(something)). Always iterate over the thing directly. That goes a long way to making your code less inelegant.
For the actual issue, you could loop over the keys and only add the item if it is in the dict. That gets a bit more complicated with your one element that is a nested lookup, but if you take it out then your code just becomes:
for item in y:
lst.append(tuple(item[key] for key in ('name', 'formatted_address', 'opening_hours', 'rating') if key in item))
You can use the get feature from dict.
y[i].get('name')
if y[i] has key 'name' returns the value or None. For nested dicts, use default value from get.
y[i].get('opening_hours', {}).get('open_now')
For data structure, I recommend to keep it as an dict, and add dicts to an list.
lst = []
lst.append({'name': "Friedman's", "address": '1187 Amsterdam Ave, New York, NY 10027, USA'})
Try this:
for i in y:
lst.append((v for k,v in i.items()))
you can use the keys method to find the keys in a dict. In your case:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in range(len(y)):
data = []
for f in fields:
if f in y[].keys():
data.append(y[i][f])
else:
data.append(None)
lst.append(set(data))
note that you can also get all the key, value pairs in a dict using the items() method. That would actually simply the code a bit. To make it even better, itterate over the set, rather than calling len(set) to:
lst=[]
fields = ('name', 'formatted_address', 'opening_hours' 'open_now', 'rating')
for i in y:
data = []
for key, value in i.items():
if key in fields:
data.append(value)
else:
data.append(None)
lst.append(set(data))

Can a python dictionary be created and updated on the go

I have to create a nested dictionary on the go inside a for loop. I have the parent dictionary data initialized to empty. Now inside the loop, I get the key to be added to the parent dictionary. And each key being again a dictionary.
data = {}
for condition
Get x, y # x is the new key
if x not in data:
data[x] ={}
data[x].update({y:1}) # or data[x][y] = 1
But I want to do the above piece in one line as below
data = {}
for condition
Get x, y # x is the new key
if x not in data:
data.update({x:{}}.update({y:1}))
Here I am getting TypeError: 'NoneType' object is not iterable. I guess this is due to the inner update (i.e. update({y:1}) is getting executed first and trying to update x which is not yet present, hence NoneType.
Is there any other way I can achieve this in one line? Or do I have the only way to create an empty dictionary first and then update the same as shown in first code piece ?
Are you trying to do automatic nested dictionary insertion? If so, you could try using a defaultdict:
from collections import defaultdict
data = defaultdict(dict)
for i in range(10):
x = "..."
y = "..."
data[x][y] = 1
print data["..."]["..."]
This prints 1
It can also be achieved data[x] = {y :1} or data.update({x: {y:1}) as mentioned by #karthikr

How can I associate a dict key to an attribute of an object within a list?

class SpreadsheetRow(object):
def __init__(self,Account1):
self.Account1=Account1
self.Account2=0
I have a while loop that fills a list of objects ,and another loop that fills a dictionary associating Var1:Account2. But, I need to get that dictionary's value into each object, if the key matches the object's Account1.
So basically, I have:
listofSpreadsheetRowObjects=[SpreadsheetRow1, SpreadsheetRow2, SpreadsheetRow3]
dict_var1_to_account2={1234:888, 1991:646, 90802:5443}
I've tried this:
for k, v in dict_var1_to_account2.iteritems():
if k in listOfSpreadsheetRowObjects:
if self.account1=k:
self.account2=v
But, it's not working, and I suspect it's my first "if" statement, because listOfSpreadsheetRowObjects is just a list of those objects. How would I access account1 of each object, so I can match them as needed?
Eventually, I should have three objects with the following information:
SpreadsheetRow
self.Account1=Account1
self.Account2=(v from my dictionary, if account1 matches the key in my dictionary)
You can use a generator expression within any() to check if any account1 attribute of those objects is equal with k:
if any(k == item.account1 for item in listOfSpreadsheetRows):
You can try to use the next function like this:
next(i for i in listOfSpreadsheetRows if k == i.account1)
If you have a dictionary d and want to get the value associated to the key x then you look up that value like this:
v = d[x]
So if your dictionary is called dict_of_account1_to_account2 and the key is self.Account1 and you want to set that value to self.Account2 then you would do:
self.Account2 = dict_of_account1_to_account2[self.Account1]
The whole point of using a dictionary is that you don't have to iterate through the entire thing to look things up.
Otherwise if you are doing this initialization of .Account2 after creating all the SpreadsheetRow objects then using self doesn't make sense, you would need to iterate through each SpreadsheetRow item and do the assignment for each one, something like this:
for row in listofSpreadsheetRowObjects:
for k, v in dict_of_account1_to_account2.iteritems():
if row.Account1 == k:
row.Account2 = v
But again, you don't have to iterate over the dictionary to make the assignment, just look up row.Account1 from the dict:
for row in listofSpreadsheetRowObjects:
row.Account2 = dict_of_account1_to_account2[row.Account1]

Categories