Suppose I have multiple functions:
type = {'a', 'b', ..., 'z'}
f={}
f['a'] = some func_a...
f['b'] = some func_b...
...
f['z'] = some func_z...
Now I want to get the outputs of them
output = {}
for t in type:
output[t] = f[t](input)
I wonder if there is any way that we can do this in one line using a loop in a different way, like
[output[t] for t in type] = [f[t](input) for t in type]
Of course, this does not work. So would there be any valid way?
You want a dictionary comprehension. It works just like a list comprehension, but instead of a single expression to form the values, you get to provide two expressions to generate both a key and a value:
output = {t: f[t](input) for t in type}
The dict comprehension produces a new dictionary object; there is no need or use for an initial output = {} line.
I'd just iterate over the items of f, as it already has the keys we need:
output = {t: func(input) for t, func in f.items()}
As a side note, instead of using separate assignments for all your f functions, just use a single dictionary definition:
f = {
'a': some_func_a,
'b': some_func_b,
# ...
'z': some_func_z,
}
type is not a great name for a variable, either, as that masks the built-in function you may sometimes want to use. You don't need to create that set separately, as iteration over f would give you the same keys, or you can use set(f) to create a set copy, or f.keys(), to get a dictionary view object over the keys of f, which acts just like a set but is 'live' in that changes to f are reflected in it.
Related
I'm following the book 'Data Science from Scratch' and this is a piece of code in it:
dd_pair = defaultdict(lambda: [0, 0])
dd_pair[2][1] = 1 # now dd_pair contains {2: [0, 1]}
Can someone please help me understand why and how it works?
defaultdict takes a data-type as an initializer. Let's consider we have a dictionary called "users" with "ID" being key and a list as value.
We have to check if a "ID" exists in the dictionary, if yes we append something to the list, else we put an empty list in that place.
So with a regular dictionary, we do something like:
users = {}
if "id1" not in users:
users["id1"] = []
users["id1"].append("log")
Now with defaultdict, all we have to do is to set an initialiser as:
from collections import defaultdict
users = defaultdict(list) # Any key not existing in the dictionary will get assigned a `list()` object, which is an empty list
users["id1"].append("log")
So coming to your code,
dd_pair = defaultdict(lambda: [0, 0])
This says, any key which doesn't exist in dd_pair will get a list of two elements initialised to 0 as their initial value. So if you just do print(dd_pair["somerandomkey"]) it should print [0,0].
Therefore, dd_pair[2][1] translates roughly to look like this:
dd_pair[2] = [0,0] # dd_pair looks like: {2:[0,0]}
dd_pair[2][1] = 1 # dd_pair looks like: {2:[0,1]}
Why the need for lambda, why not just use [0,0] ?
The defaultdict constructor expects a callable (The constructor actually expects a default_factory, check out Python docs). In extremely simple terms, if we do defaultdict(somevar), somevar() should be valid.
So, if you just pass [0,0] to defaultdict it'll be wrong since [0,0]() is not valid at all.
So what you need is a function which returns [0,0], which can be simply implemented using lambda:[0,0]. (To verify, just do (lambda:[0,0])() , it will return [0,0]).
One more way is to create a class for your specific type, which is better explained in this answer: https://stackoverflow.com/a/36320098/
I have a list like this-
send_recv_pairs = [(['produce_send'], ['consume_recv']), (['Send'], ['Recv']), (['sender2'], ['receiver2'])]
I want something like
[ {['produce_send']:['consume_recv']},{['Send']:['Recv']},{['sender2']:['receiver2']}
How to do this?
You can not use list as the key of dictionary.
This Article explain the concept,
https://wiki.python.org/moin/DictionaryKeys
To be used as a dictionary key, an object must support the hash function (e.g. through hash), equality comparison (e.g. through eq or cmp), and must satisfy the correctness condition above.
And
lists do not provide a valid hash method.
>>> d = {['a']: 1}
TypeError: unhashable type: 'list'
If you want to specifically differentiate the key values you can use tuple as they hash able
{ (i[0][0], ): (i[1][0], ) for i in send_recv_pairs}
{('Send',): ('Recv',),
('produce_send',): ('consume_recv',),
('sender2',): ('receiver2',)}
You can't have lists as keys, only hashable types - strings, numbers, None and such.
If you still want to use a dictionary knowing that, then:
d={}
for tup in send_recv_pairs:
d[tup[0][0]]=tup[1]
If you want the value to be string as well, use tup[1][0] instead of tup[1]
As a one liner:
d={tup[0][0]]:tup[1] for tup in list} #tup[1][0] if you want values as strings
You can check it over here, in the second way of creating distionary.
https://developmentality.wordpress.com/2012/03/30/three-ways-of-creating-dictionaries-in-python/
A Simple way of doing it,
First of all, your tuple is tuple of lists, so better change it to tuple of strings (It makes more sense I guess)
Anyway simple way of working with your current tuple list can be like :
mydict = {}
for i in send_recv_pairs:
print i
mydict[i[0][0]]= i[1][0]
As others pointed out, you cannot use list as key to dictionary. So the term i[0][0] first takes the first element from the tuple - which is a list- and then the first element of list, which is the only element anyway for you.
Do you mean like this?
send_recv_pairs = [(['produce_send'], ['consume_recv']),
(['Send'], ['Recv']),
(['sender2'], ['receiver2'])]
send_recv_dict = {e[0][0]: e[1][0] for e in send_recv_pairs}
Resulting in...
>>> {'produce_send': 'consume_recv', 'Send': 'Recv', 'sender2': 'receiver2'}
As mentioned in other answers, you cannot use a list as a dictionary key as it is not hashable (see links in other answers).
You can therefore just use the values in your lists (assuming they stay as simple as in your example) to create the following two possibilities:
send_recv_pairs = [(['produce_send'], ['consume_recv']), (['Send'], ['Recv']), (['sender2'], ['receiver2'])]
result1 = {}
for t in send_recv_pairs:
result1[t[0][0]] = t[1]
# without any lists
result2 = {}
for t in send_recv_pairs:
result2[t[0][0]] = t[1][0]
Which respectively gives:
>>> result1
{'produce_send': ['consume_recv'], 'Send': ['Recv'], 'sender2': ['receiver2']}
>>> result2
{'produce_send': 'consume_recv', 'Send': 'Recv', 'sender2': 'receiver2'}
Try like this:
res = { x[0]: x[1] for x in pairs } # or x[0][0]: x[1][0] if you wanna store inner values without list-wrapper
It's for Python 3 and when keys are unique. If you need collect list of values per key, instead of single value, than you may use something like itertools.groupby or map+reduce. Wrote about this in comments and I'll provide example.
And yes, list cannot store key-values, only dict's, but maybe it's just typo in question.
You can not use list as the dictionary key, but instead you may type-cast it as tuple to create the dict object.
Below is the sample example using a dictionary comprehension:
>>> send_recv_pairs = [(['produce_send'], ['consume_recv']), (['Send'], ['Recv']), (['sender2'], ['receiver2'])]
>>> {tuple(k): v for k, v in send_recv_pairs}
{('sender2',): ['receiver2'], ('produce_send',): ['consume_recv'], ('Send',): ['Recv']}
For details, take a look at: Why can't I use a list as a dict key in python?
However if your nested tuple pairs were not list, but any other hashable object pairs, you may have type-casted it to dict for getting the desired result. For example:
>>> my_list = [('key1', 'value1'), ('key2', 'value2')]
>>> dict(my_list)
{'key1': 'value1', 'key2': 'value2'}
I am trying to return two dictionaries. person_to_friends and person_to_networks are given functions, and profiles_file is a text file.
What I wrote is:
def load_profiles(profiles_file, person_to_friends, person_to_networks):
"""
(file, dict of {str : list of strs}, dict of {str : list of strs}) -> NoneType
Update person to friends and person to networks dictionaries to include
the data in open file.
"""
profiles_file = open('data.txt', 'r')
person_to_friends = person_to_friends(profiles_file)
person_to_networks = person_to_networks(profiles_file)
return person_to_friends, person_to_networks
This only gives me person_to_friends dictionary..Could anyone can help this problem?
What I want to return is
{person_to_friends}
{person_to_networks}
Simply do:
return (person_to_friends, person_to_networks)
and when you call the function you need to unpack the return value:
person_to_friends, person_to_networks = load_profiles(var1, var2, var3)
You can return only one value (this value can be a tuple, as in your case). However, you can yield as much values as you need:
def load_profiles(profiles_file, person_to_friends, person_to_networks):
"""
(file, dict of {str : list of strs}, dict of {str : list of strs}) -> NoneType
Update person to friends and person to networks dictionaries to include
the data in open file.
"""
profiles_file = open('data.txt', 'r')
person_to_friends = person_to_friends(profiles_file)
person_to_networks = person_to_networks(profiles_file)
yield person_to_friends # you can do it without temp variable, obv.
yield person_to_networks
The difference is that with yield statement you don't construct a temporary tuple just to return two results at once. However, getting the values out of your "function" (that became a generator) will be slightly more difficult:
profiles = load_profiles(your args)
will not actually run your function at all, it just initializes a generator. To actually get values, you'll need to:
person_to_friends = next(profiles)
person_to_networks = next(profiles)
or just do a loop:
for result in load_profiles(your args):
do_something_with_your_dictionaries
So your function will return one value: the initialized generator object. Iterating over it in a loop (it can be for loop, map, filter, list(your_generator) or something else) or just calling next(your_generator) will give you both dictionaries you actually need.
The way you are returning two dictionaries is fine, something funny must be going on in the other parts of the code, if your remove them, everything works fine:
def load_profiles():
person_to_friends = {'a' : 1}
person_to_networks = {'b' : 2}
return person_to_friends, person_to_networks
Result:
>>> load_profiles()
({'a': 1}, {'b': 2})
>>> dict_1, dict_2 = load_profiles()
>>> dict_1
{'a': 1}
>>> dict_2
{'b': 2}
Your docstring states that the function parameter person_to_friends is a
dict of {str : list of strs}
But then you call it as though it were a function and overwrite it with the result:
person_to_friends = person_to_friends(profiles_file)
Is this a mistake in the docstring, or the code?
Possibly you are masking the real function definition by having a locally defined variable of the same name (ie the parameter). In general it is bad practice to override a variable of one type (eg function) with another vastly different type (eg dict) - although there are exceptions to this.
maybe you can try
class temp(a, b):
return dict(a=a, b=b)
I've tried my best to figure this out, but I can't for the life of me. I have a dictionary with many different values in it, including another dictionary. Before setting the values for the dictionary within the dictionary, I try to set the values equal to a "blank" dictionary such that in subsequent steps I can update it.
The short story is: I have two lines that somehow are changing a dictionary that I wouldn't expect. Given some dicts:
blankresiduedict = {stuff:[stuff], stuff:[stuff]}; blankidentifiers = {stuff:stuff, stuff:stuff}
the lines
self.pdb_chain_dict['1MH9_B'] = (blankresiduedict.copy(),blankidentifiers.copy())
self.pdb_chain_dict['1MH9_B'][0][(stuff)][0] = residuedict[('A','D','41')]
are somehow changing the values of blankresiduedict to be equal to residuedict.
Any idea how this is happening? There is literally no other reference to blankresiduedict in that section of code, and when I look at the output, blankresiduedict starts out accurate and then with each loop keeps changing value to equal whatever residuedict was for that loop.
(Below is a more detailed description)
This is a small part of a very large project, so some of this may really be hard to represent in a compact form. I'll do my best to eliminate the unnecessary stuff. This is a method within a class that I am trying to use to update the dictionary for the class instance.
blankresiduedict = {}
blankidentifiers = {}
self.allowmultiples = True
self.ancestorline = [
'1MH9',
'A', 'D', '41',
'A', 'D', '43',
'A', 'T', '130',
#etc...
]
self.no_key_residues = 6
self.pdb_chain_dict = {
'1MH9_B': (
{
('A','D','41'): [('B','D','41')],
('A','D','43'): [('B','D','43')],
('A','T','130'): [('B','T','130')]
},
#{identifiers dictionary}
),
'1MH9_C': (
#{etc},{etc}
),
# etc...
}
for i in range(1, (3*self.no_key_residues)+1, 3): # Using this loop structure allows a variable number of key residues to be given
if not self.allowmultiples:
raise Exception("Do some stuff here")
else:
blankresiduedict[(self.ancestorline[i],self.ancestorline[i+1],self.ancestorline[i+2])] = [('-','-','-')]
blankidentifiers = {'EC Num':'-','Sprot':'-','Class':'-','Keywords':'-','Title':'-','SeqRepr':'-'}
### Begin some loop structure, where for every loop, the following is basically happening
residuedict = {
('A','D','41'): ('B','D','10'),
('A','D','43'): ('B','D','12')
} #in actuality this value would change for every loop, but just showing what a typical loop would look like
self.pdb_chain_dict['1MH9_B'] = (blankresiduedict.copy(),blankidentifiers.copy())
self.pdb_chain_dict['1MH9_B'][0][('A','D','41')][0] = residuedict[('A','D','41')]
What should happen here is that the value in the pdb_chain_dict is set to the the tuple of two blank dictionaries ({residuedict},{identifiers}) I'm mostly leaving the identifier dictionary alone in this example because it has the exact same problem. However, what I'm finding is that the blankresiduedict is actually changing. And, after doing a lot of testing, the line where it is changing is self.pdb_chain_dict['1MH9_B'][0][('A,'D','41')][0] = residuedict[('A','D','41')].
This makes no sense to me...blankresiduedict is not even involved, yet somehow it's value is being changed in that step.
That's because a copy of a dictionary is not a deep copy, and your dict values are lists, which are mutable. Here's a minimal example that reproduces your issue:
d1 = {"foo": [1, 2, 3]}
d2 = d1.copy()
# Add a new element to d2 to show that the copy worked
d2["bar"] = []
# The two dicts are different.
print d1
print d2
# However, the list wasn't copied
# it's the same object that shows up in 2 different dicts
print d1["foo"] is d2["foo"]
# So that's what happens in your code: you're mutating the list.
d1["foo"].append(5)
print d2["foo"]
I have a set of data that looks like so:
OutletCntrTemp|25degreesC|ok
InletTemp|17degreesC|ok
PCHTemp|46degreesC|ok
P0ThermMargin|-57degreesC|ok
P1ThermMargin|-59degreesC|ok
P0DIMMTemp|27degreesC|ok
P1DIMMTemp|27degreesC|ok
HSC0InputPower|60Watts|ok
HSC0InputVolt|12.46Volts|ok
CPU0Tjmax|90degreesC|ok
......
Now I want to loop through this data and create a list or a tuple in a function and return each row but name that tuple using the first part of the string:
CPUTjmax = ('90degreesC','ok')
now i did some spliting up of the string via | but hit a wall when i tried to use string[0] = (string[1],string[2]) to define the tuple.
Could anyone give me a pointer here please.
Ric
What you can do is, create a dict, and add them as key:value pair in it:
>>> d = dict()
>>>
>>> s = 'CPU0Tjmax|90degreesC|ok'
>>> li = s.split("|")
>>>
>>> d[li[0]] = (li[1], li[2])
>>> d
{'CPU0Tjmax': ('90degreesC', 'ok')}
You almost certainly don't want to create variables, use a dict instead:
data = [
'CPU0Tjmax|90degreesC|ok',
'InletTemp|17degreesC|ok'
]
d = {el[0]: tuple(el[1:]) for el in (item.split('|') for item in data)}
# {'InletTemp': ('17degreesC', 'ok'), 'CPU0Tjmax': ('90degreesC', 'ok')}
The other answers are good. Here is one more way, similar to the answer using locals(). You just create an empty object, and fill its __dict__:
class X(object):
pass
Var = X()
for ...:
Var.__dict__[string[0]] = (string[1], string[2])
#now you can refer to your vars as Var.whatever
if Var.InletTemp[1] != 'ok':
...
Use should definitely use a dictionary variable.
For completeness here a non-standard solution for creating new local variables:
for line in open("data.dat"):
e=line.split("|")
locals()[e[0]] = ( e[1], e[2] )
Internally, the local variables are also a dictionary which you can access with locals().
However, as the documentation says:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.