Merge two dictionaries with keys only from the first dict - python

I want to merge two dictionaries so that the resulting dict has keys from the first dict and values from the first and second.
>>> A = {'AB': 'a', 'A': 'a'}
>>> B = {'AB': 'b', 'B': 'b'}
>>> merge_left(A, B)
{'AB': 'b', 'A': 'a'}
This is somewhat similar to a left outer join used in merging database tables in that one side is used as the "base" and the other side is compared to it.
Here is a table of what value each key should have in the resulting dict.
Possible Situations
Key in A
Key not in A
Key in B
Use B's value
Don't include
Key not in B
Use A's value
N/A
Is there a function merge_left or something similar that returns the dict above?

I used dict.get's ability to return a default value to make a fairly short merge_left function. This uses a dict-comprehension over key, value pairs of the first dict and checks them against the second.
def merge_left(defaults, override):
return {key, override.get(key, default) for key, default in defaults.items()}
Since this function is just returning a dict-comprehension, you can "inline" it directly into your code.
>>> A = {'AB': 'a', 'A': 'a'}
>>> B = {'AB': 'b', 'B': 'b'}
>>> {k: B.get(k, a) for k, a in A.items()}
{'AB': 'b', 'A': 'a'}

Related

Can this conditional be shortened?

Is it possible to just use .get() function from dictionary for this? Is this the best we can do to shorten this piece of code?
n_dict is a Dict type (uppercase D) and NES is just a list of str
eted_info = {}
for key in n_dict:
if key in NES:
eted_info[key] = n_dict[key]
I'm just curious if there is a better / more pythonic way to retrieve a value, like C# has with TryGetValue.
I think a dictionary comprehension and using n_dict.items() is the cleanest way of doing this
n_dict = {'a': 1, 'b': 2, 'c': 3}
NES = ['a', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
eted_info = {key:value for key,value in n_dict.items() if key in NES}
print(eted_info)
RESULT
{'a': 1, 'c': 3}
You can do something with dictionary comprehension like this:
eted_info = {key: n_dict[key] for key in n_dict if key in NES}
If you want to avoid the O(n^2) operation of iterating through each item in NES for each item in n_dict, you can build a list of keys as a set intersection and iterate through that:
eted_info = {k: n_dict[k] for k in set(n_dict) & set(NES)}
Iterate over keys in NES; use n_dict.get.get with a default of None; conditionally add to eted_info.
for key in NES:
v = n_dict.get(key,None)
if v: eted_info[key] = v
This will only iterate over the list once regardless of the length of n_dict.
Assumes all values in n_dict are truthy. Other placeholders could be used for the default value.

Match two dict and change keys in first if keys exists in second

I have two dict:
a={'a':'A','b':'B'}
b={'a':123,'b':123}
I need check if keys 'a' and 'b' (two elements in example, in real code, it will be more) in dict b, exist in dict a. If so, I should change the keys in dict b using values from dict a:
Expected result:
b={'A':123, 'B': 123}
How I can do it?
{a[k] if k in a else k: v for k, v in b.items()}
This is how it's done:
a={'a':'A','b':'B'}
b={'a':123,'b':123}
c = {}
for key in a.keys():
if key in b.keys():
c.update({a[key]:b[key]})
The other answers so far ignore the question which wants the code to:
change keys in dict in b for values from dict a
I infer that any data in b, for which there isn't a replacement key in a, should be left alone. So walking the keys of a creating a new dictionary c won't work. We need to modify b directly. A fun way to do this is via the pop() method which we normally associate with lists but also works on dictionaries:
a = {'a': 'A', 'b': 'B'}
b = {'a': 123, 'b': 124, 'C': 125}
for key in list(b): # need a *copy* of old keys in b
if key in a:
b[a[key]] = b.pop(key) # copy data to new key, remove old key
print(b)
OUTPUT
> python3 test.py
{'C': 125, 'A': 123, 'B': 124}
>

changing a dictionary in python and make a new one

I have a dictionary in python like this example:
small example:
d = {'chr12:112843810-112843817': 'CGTAGAG', 'chr16:48394513-48394520': 'TTTAAAC'}
the value of this dictionary is a sequence of characters and the characters can only be A, C, G or T. but I want to make a new dictionary in which the keys are similar but values are different. in fact in new dictionary the sequence of characters would have 2 changes:
1- it must be reversed (direction). for example "AGT" would be "TGA".
2- I want to convert: A -> T , T -> A , C -> G , G -> C.
considering 2 above items, AGTCC would be converted to GGACT
here is the expected output for the small example:
expected output:
d2 = {'chr12:112843810-112843817': 'CTCTACG', 'chr16:48394513-48394520': 'GTTTAAA'}
I am trying to do that in python using the following code:
def reverse_complement(dict):
for v in dict:
complement = {'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A'}
return [complement[base] for base in v[::-1]]
but it does not return what would like to get. do you know how to fix it?
for v in dict iterates the keys, not the values. You should use items to iterate over key-value pairs.
The return statement causes the function to return after the first iteration.
dict is a bad variable name (d is probably worse, but at least it does not shadow a built-in name)
You can use a dict comphrension:
def reverse_complement(d):
complement = {'A': 'T', 'C': 'G', 'G': 'C', 'T': 'A'}
return {k: ''.join(complement[base] for base in v[::-1]) for k, v in d.items()}
or with str.translate:
def reverse_complement(d):
table = str.maketrans('ACGT', 'TGCA')
return {k: v[::-1].translate(table) for k, v in d.items()}
Here another solution with string replacement methods. This might be faster.
the complement method does the inversion by fist setting the string to lower case and then doing the renaming based on lower to upper case.
The "[::-1]" reverses the order and the rest is a dictionary comprehension, that creates a new dictionary
complement = lambda s: s.lower().replace("g","C").replace("c","G").replace("t","A").replace("a","T")
d2 = { k:complement(v)[::-1] for k,v in d.items() }
Similar to first answer by #DeepSpace, you could map the complements in-place with reversed():
d = {'chr12:112843810-112843817': 'CGTAGAG', 'chr16:48394513-48394520': 'TTTAAAC'}
complements = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C'}
for k, v in d.items():
d[k] = ''.join(map(complements.get, reversed(v)))
print(d)
# {'chr12:112843810-112843817': 'CTCTACG', 'chr16:48394513-48394520': 'GTTTAAA'}
You can also rebuild new dictionary:
d2 = {k: ''.join(map(complements.get, reversed(v))) for k, v in d.items()}
print(d2)
# {'chr12:112843810-112843817': 'CTCTACG', 'chr16:48394513-48394520': 'GTTTAAA'}
Note: ''.join(map(complements.get, reversed(v))) is just another way of writing ''.join(complemements.get(x) for x in reversed(v)).

Insertion order and Duplicate Keys in Dictionary

I'm using python 3.7.
I have a dictionary something like this.
dict = { 'a' :2 , 'a' :1 , 'b':3 , 'c':4}
print(dict)
O/P ={'a' : 1 , 'b' :2 , 'c':3 }
Now In python 3.7 dictionary must maintain insertion order .So expected o/p will be {'a':2 , 'b':3 , 'c' :4} , but ('a',2) is being removed from dictionary instead of('a',1) .Why is this happening ??Is there any rule for removing duplicate keys in python ??
From the Python documentation:
The main operations on a dictionary are storing a value with some key and extracting the value given the key. It is also possible to delete a key:value pair with del. If you store using a key that is already in use, the old value associated with that key is forgotten. It is an error to extract a value using a non-existent key.
See: https://docs.python.org/3/tutorial/datastructures.html
Maintaining insertion order is concerned with different keys:
>>> dct = {'a': 1, 'b': 2} # do NOT shadow built-in name 'dict'
>>> print(dct)
{'a': 1, 'b': 2}
# and not
{'b': 2, 'a': 1} # which was totally possible before Python3.6
When receiving multiple values for the same key, the last one provided wins:
>>> dct = {'a': 3, 'a': 1, 'b': 2}
>>> print(dct)
{'a': 1, 'b': 2}
This is similar to the following scenario:
>>> dct = {}
>>> dct['a'] = 3
>>> dct['a'] = 1
>>> dct['b'] = 2
Would you expect dct['a'] to be 3 now because of the "insertion order"? Certainly not!
The value assigned to a key can be anything and even duplicated since it merely a value. Keys however, are similar to a variable name. Like in many programming languages, if a variable name is used again in the same scope or method, the first variable and its value is overwritten by the second since it is more recent.
In this case it may be more appropriate to to assign a different key (think of keys as identifiers) to the same value if that is your wish. Like this
dict = { 2: 'a', 1: 'a', 3:'b', 4:'c'}
print(dict)
O/P = {1: 'a', 2: 'a', 3: 'b', 4: 'c'}

Python dictionary.keys() error

I am trying to use the .keys() and instead of getting a list of the keys like
always have in the past. However I get this.
b = { 'video':0, 'music':23 }
k = b.keys()
print( k[0] )
>>>TypeError: 'dict_keys' object does not support indexing
print( k )
dict_keys(['music', 'video'])
it should just print ['music', 'video'] unless I'm going crazy.
What's going on?
Python 3 changed the behavior of dict.keys such that it now returns a dict_keys object, which is iterable but not indexable (it's like the old dict.iterkeys, which is gone now). You can get the Python 2 result back with an explicit call to list:
>>> b = { 'video':0, 'music':23 }
>>> k = list(b.keys())
>>> k
['music', 'video']
or just
>>> list(b)
['music', 'video']
If you assigned k like so:
k = list(b.keys())
your code will work.
As the error says, the dict_keys type does not support indexing.
This is one of the breaking changes between Python 2 and 3.
In Python 2:
>>> help(dict.keys)
keys(...)
D.keys() -> list of D's keys
In Python 3:
>>> help(dict.keys)
keys(...)
D.keys() -> a set-like object providing a view on D's keys
This change in behavior makes a lot of sense since a dict is semantically unordered and its keys are unique - just like a set.
This change means that you don't have to create a new list of keys every time you want to do some kind of set comparison with a dict's keys.
Getting the same behavior in 2 and 3
To help transition to Python 3, Python 2.7 has another dict method, viewkeys. The viewkeys method is most similar to Python 3's dict.keys method:
>>> d
{'a': None, 'c': None, 'b': None, 'd': None}
>>> for k in d.viewkeys(): print k
...
a
c
b
d
>>> d.viewkeys() & set('abc')
set(['a', 'c', 'b'])
In Python 3, the closest analog to the old behavior is to pass dict.keys() to list:
>>> d
{'d': None, 'a': None, 'c': None, 'b': None}
>>> list(d.keys())
['d', 'a', 'c', 'b']
Or just pass the dict to list, since a dict will iterate over its keys anyways:
>>> list(d)
['d', 'a', 'c', 'b']
You could create a utility functions to abstract the behavior over 2 and 3:
if hasattr(dict, 'viewkeys'): # Python 2.7
def keys(d):
return d.viewkeys()
else: # Python 3
def keys(d):
return d.keys()
And pass a dict to list to get the list form, and in both 2 and 3, you'll get the same output:
>>> d
{'b': None, 'a': None, 'c': None, 'd': None}
>>> keys(d)
dict_keys(['b', 'a', 'c', 'd'])
>>> list(d)
['b', 'a', 'c', 'd']
If you simply want a list of keys from a dictionary you can directly do like this:
b = {"name": "xyz", "class":"abc", "college": "qwert"}
key_list = list(b)
key_list will contain all the key names as a list, though, this will not repeats a key, if found more than once. Duplicate keys will be counted as one.
import random
b = { 'video':0, 'music':23,"picture":12 }
random.choice(tuple(b.items()))
# Returns a random dictionary entry as a tuple:
# ('music', 23)

Categories

Resources