Can you guys think of any one liners equal to if/else statements:
d = dict()
key = 1, 2
if key in d:
d[key]['idx'] += [2]
else:
d[key] = {'idx': [2]}
print d
?
EDIT:
Thanks guys. You narrowed me to collection.defaultdict & dict.setdafault and with this in mind I was able to achieve what I wanted:
from collections import defaultdict
d = dict()
key = 1, 2
d.setdefault(key, {'idx': []})
d[key]['idx'] += [2]
Maybe it is not one liner as it spreads over 2 lines (setdefault() call and then in place addition), but looks nicer though.
But still, if anyone have any ideas how to make it real one liner please share it.
Sometimes it is better to do things in multiple lines, this is one of those cases. However sometimes it is reasonable to try to avoid this sort of "does this key exist" logic, and to do that you can use collections.defaultdict or dict.setdefault(). And now just for fun, here is a horrible one-liner that you should not use (but is equivalent in behavior to your if/else):
d.setdefault(key, {'idx': []})['idx'] += [2] if d[key]['idx'] else [1]
Note that this is less efficient than your original version, because it requires additional lookups, and creates unnecessary objects each time you use it.
Maybe:
d = dict()
key = 1,2
d[key] = (d[key]['idx'] + [2] if key in d and 'idx' in d[key] else {'idx': [2]})
key=1,2
d={key:'idx'}
d[key]['idx'] = d[key]['idx']+[2] if key in d else ['2']
Related
i was asked to write a code including a function- reverse_dict_in_place(d)
which switches between keys and values of the inputed dictionary
without changing the dictionary's location in memory (in place).
however, testing it with id() function shows that all my solutions do change dictionaries memory location..
def reverse_dict_in_place(d):
d={y:x for x,y in d.items()}
return d
Alternative to current ones which allows values to be same as keys. Works in mostly the same way though, however once again no two values may be the same.
def reverse_dict_in_place(d):
copy = d.copy().items()
d.clear()
for k, v in copy:
d[v] = k
return d
>>> x = {0: 1, 1: 2}
>>> y = reverse_dict_in_place(x)
>>> id(x) == id(y)
True
>>>
Some assumptions for this to work (thanks to all the users who pointed these out):
There are no duplicate values
There are no non-hashable values
There are no values that are also keys
If you're comfortable with those assumption then I think this should work:
def reverse_dict_in_place(d):
for k,v in d.items():
del d[k]
d[v] = k
return d
Extending on Gad suggestion, you could use dict comprehension:
reversed = {v: k for k, v in d.items()}
Where d is a dict, and the same assumptions apply:
There are no duplicate values
There are no non-hashable values
There are no values that are also keys
This would not work, without modification, for nested dicts.
Note: #NightShade has posted a similar answer as my below answer, earlier than I posted.
You can try this:
def reverse_dict_in_place(d):
d_copy = d.copy()
d.clear()
for k in d_copy:
d[d_copy[k]] = k
This would work even if one of the dictionary's values happens to also be a key (as tested out below)
Testing it out:
my_dict = {1:1, 2:'two', 3:'three'}
reverse_dict_in_place(my_dict)
print (my_dict)
Output:
{1: 1, 'two': 2, 'three': 3}
I have a dictionary of a list of dictionaries. something like below:
x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
The length of the lists (values) is the same for all keys of dict x.
I want to get the length of any one value i.e. a list without having to go through the obvious method -> get the keys, use len(x[keys[0]]) to get the length.
my code for this as of now:
val = None
for key in x.keys():
val = x[key]
break
#break after the first iteration as the length of the lists is the same for any key
try:
what_i_Want = len(val)
except TypeError:
print 'val wasn't set'
i am not happy with this, can be made more 'pythonic' i believe.
This is most efficient way, since we don't create any intermediate lists.
print len(x[next(iter(x))]) # 2
Note: For this method to work, the dictionary should have atleast one key in it.
What about this:
val = x[x.keys()[0]]
or alternatively:
val = x.values()[0]
and then your answer is
len(val)
Some of the other solutions (posted by thefourtheye and gnibbler) are better because they are not creating an intermediate list. I added this response merely as an easy to remember and obvious option, not a solution for time-efficient usage.
Works ok in Python2 or Python3
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> next(len(i) for i in x.values())
2
This is better for Python2 as it avoids making a list of the values. Works well in Python3 too
>>> next(len(x[k]) for k in x)
2
Using next and iter:
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> val = next(iter(x.values()), None) # Use `itervalues` in Python 2.x
>>> val
[{'q': 2, 'p': 1}, {'q': 5, 'p': 4}]
>>> len(val)
2
>>> x = {}
>>> val = next(iter(x.values()), None) # `None`: default value
>>> val is None
True
>>> x = {'a':[{'p':1, 'q':2}, {'p':4, 'q':5}], 'b':[{'p':6, 'q':1}, {'p':10, 'q':12}]}
>>> len(x.values()[0])
2
Here, x.values gives you a list of all values then you can get length of any one value from it.
Is it possible to replace all values in a dictionary, regardless of value, with the integer 1?
Thank you!
Sure, you can do something like:
d = {x: 1 for x in d}
That creates a new dictionary d that maps every key in d (the old one) to 1.
You can use a dict comprehension (as others have said) to create a new dictionary with the same keys as the old dictionary, or, if you need to do the whole thing in place:
for k in d:
d[k] = 1
If you're really fond of 1-liners, you can do it in place using update:
d.update( (k,1) for k in d )
a = {1:2, 2:2,3:2}
a = {x:1 for (x,_) in a.iteritems()}
print a
{1: 1, 2: 1, 3: 1}
Yes, it's possible. Iterate through every key in the dictionary and set the related value to 1.
If a and b are 2 dictionaries:
a = {'UK':'http://www.uk.com', 'COM':['http://www.uk.com','http://www.michaeljackson.com']}
bb = {'Australia': 'http://www.australia.com', 'COM':['http://www.Australia.com', 'http://www.rafaelnadal.com','http://www.rogerfederer.com']}
I want to merge them to get
{'Australia': ['http://www.australia.com'], 'COM': ['http://www.uk.com', 'http://www.michaeljackson.com', 'http://www.Australia.com', 'http://www.rafaelnadal.com', 'http://www.rogerfederer.com'], 'UK': ['http://www.uk.com']}
I want to union them i.e.
How to do it in Python without overwwriting and replacing any value?
Use a defaultdict:
from collections import defaultdict
d = defaultdict(list)
for dd in (a,bb):
for k,v in dd.items():
#Added this check to make extending work for cases where
#the value is a string.
v = (v,) if isinstance(v,basestring) else v #basestring is just str in py3k.
d[k].extend(v)
(but this is pretty much what I told you in my earlier answer)
This now works if your input dictionaries look like
{'Australia':['http://www.australia.com']}
or like:
{'Australia':'http://www.australia.com'}
However, I would advise against the latter form. In general, I think it's a good idea to keep all the keys/values of a dictionary looking the same (at least if you want to treat all the items the same as in this question). That means that if one value is a list, it's a good idea for all of them to be a list.
If you really insist on keeping things this way:
d = {}
for dd in (a,b):
for k,v in dd.items():
if(not isinstance(v,list)):
v = [v]
try:
d[k].extend(v)
except KeyError: #no key, no problem, just add it to the dict.
d[k] = v
I have one defaultdict(list) and other normal dictionary
A = {1:["blah", "nire"], 2:["fooblah"], 3:["blahblah"]}
B = {1: "something" ,2:"somethingsomething"}
now lets say that i have something like this
missing_value = "fill_this"
Now, first I want to find what are the keys in B missing from A (like 3 is missing)
and then set those keys to the values missing_value?
What is the pythonic way to do this?
Thanks
You can use setdefault:
for k in A:
B.setdefault(k, "fill_this")
This is essentially the same as the longer:
for k in A:
if k not in B:
B[k] = "fill_this"
However, since setdefault only needs to lookup each k once, setdefault is faster than this "test&set" solution.
Alternatively (and probably slower), determine the set difference and set (no pun intended) those values:
for k in set(A).difference(B):
B[k] = "fill_this"
The solution is to go through A and update B where necessary. It would have O(len(A)) complexity:
for key in A:
if key not in B:
B[key] = missing_value
Here's one way:
def test():
A = {1:"blah", 2:"fooblah", 3:"blahblah"}
B = {1: "something" ,2:"somethingsomething"}
keys=set(A.keys()).difference(set(B.keys()))
for k in keys:
B[k]="missing"
print (B)
When I've seen a need for this, there were a standard set of keys to be checked in a dict of dicts. If that's the case and if performance is not a significant factor, I think this is the cleanest syntax.
template = {k: default for k in domain}
for k, d in dicts.items():
dicts[k] = template.copy().update(d)