Drop keys from a dictionary based on a string value in Python - python

Why doesn't this work:
I have a dictionary inside dictionary
{'rrr-rrr/CCC-3/FFFF-1': {'ActiveSet': '0'},
'rrr-rrr/CCC-4/FFFF-1': {'ActiveSet': '1'},
...}
And I need to drop keys where CCC is 3 (CCC-3).
The way I've tried is this:
my_dict = {k: v
for k, v in my_dict.iteritems()
if k.split('/')[1].split('-')[1]!= 3
}
And there is no error with this code, but nothing happens. I've tried also to make new key inside inner dict from that CCC number but that doesn't work too.
Desired output:
{'rrr-rrr/CCC-4/FFFF-1': {'ActiveSet': '1'},
...}

As Jon Clements mentioned, you're comparing a string to an integer, so your if condition will never evaluate to true.
As a fix, I'd go with something more like:
val = 3
my_dict = {k : v
for k, v in my_dict.iteritems()
if 'CCC-{}'.format(val) not in k
}
This way, you don't have to hardcode your split and indexing. Note that, if you have keys of the form CCC-<number> where the number is two or more digits, you'll need to match CCC-{}/, as Danil Speransky smartly observes in his answer.
Note that the python 3 equivalent of dict.iteritems is dict.items.

Your code doesn't work because you compare an integer and a string. Change it to '3':
if k.split('/')[1].split('-')[1] != '3'
Or simpler:
if 'CCC-3/' not in k
I have added / to not exclude CCC-32.

You can just search for your desired pattern in the key:
new_data = {a:b for a, b in d.items() if "CCC-3" not in a}

Related

List comprehension for dictionary – condition for adding key if value is not null

Having list comprehension of dictionaries. My goal is to create dictionary with one key if key["formula"] does not exist or dictionary with two keys if formula exists.
Currently having something like this and it works
cols = [{"header":k, **(({"formula":v["formula"]}) if v.get("formula") else {})} for k,v in inp["cols"].items()]
Is there any shorter / more elegant way to gain the same effect?
Edit (expected output): for clarification, what I need to achieve is
inp = {"cols":{"header1":{"formula":"test"}}}
cols = [{"header":k, **(({"formula":v["formula"]}) if v.get("formula") else {})} for k,v in inp["cols"].items()]
->
[{'header': 'header1', 'formula': 'test'}]
inp = {"cols":{"header1":{"notformula":"test"}}}
cols = [{"header":k, **(({"formula":v["formula"]}) if v.get("formula") else {})} for k,v in inp["cols"].items()]
->
[{'header': 'header1'}]
You can improve it slightly using the dict union operator introduced in Python 3.9. Here it is with extra line breaks for readability and PEP 8 compliance.
cols = [
{"header": k} | ({"formula": v["formula"]} if "formula" in v else {})
for k, v in inp["cols"].items()
]
I've also replaced your v.get("formula") with an in check. v.get("formula") is falsy if v is {"formula": []}, for instance, which you may, but probably don't, want.
I would consider extracting the logic on the second line into a function.

Read a string in dictionary values and replace a specific character

I have a dict in which each value is a string. In some values, this string has "-" that I would like to remove. I have been told that it is not possible to replace the values of a dict. Is that right?
mydict
'GCA_000010565.1_genomic Ribosomal_L10:': '-TRAEKEAIIQELKEKFKEARVAVLADYRGLNV-------AEATRLRRRLREAGCEFKVAKNTLTGLAARQAGLE-----GLDPYLEGPIAIAFG-VDPVAPAKVLSDF--',
I would wish something like
mydict
'GCA_000010565.1_genomic Ribosomal_L10:': 'TRAEKEAIIQELKEKFKEARVAVLADYRGLNVAEATRLRRRLREAGCEFKVAKNTLTGLAARQAGLEGLDPYLEGPIAIAFGVDPVAPAKVLSDF',
Absolutly you can, just iterate over the mappings key/value, and change the associated value by the processed one
d = {'superkey': "foo--bar", 'superkey2': "--foo--bar",
'GCA_000010565.1_genomic Ribosomal_L10:': '-TRAEKEAIIQELKEKFKEARVAVLADYRGLNV-------AEATRLRRRLREAGCEFKVAKNTLTGLAARQAGLE-----GLDPYLEGPIAIAFG-VDPVAPAKVLSDF--', }
# LOOP version
for k, v in d.items():
d[k] = v.replace("-", "")
# DICT COMPREHENSION version
d = {k: v.replace("-", "") for k, v in d.items()}
print(d) # {'superkey': 'foobar', 'superkey2': 'foobar',
'GCA_000010565.1_genomic Ribosomal_L10:': 'TRAEKEAIIQELKEKFKEARVAVLADYRGLNVAEATRLRRRLREAGCEFKVAKNTLTGLAARQAGLEGLDPYLEGPIAIAFGVDPVAPAKVLSDF'}
Yes it is possible. You can simply use
mydict['GCA_000010565.1_genomic Ribosomal_L10:'] = mydict['GCA_000010565.1_genomic Ribosomal_L10:'].replace("-","")
No, you've been told BS. The solution:
for k in mydict:
mydict[k] = mydict[k].replace('-', '')

Check if value of one dictionary is the key for the other

I basically want to check if the value in one dictionary is the key in the other.
So for example, I have two dictionaries
a = {armani: jeans, dolce: gabbana}
b = {jeans: robo, jobs: versace}
I wrote code to do the check such that it only obtains the values that is the key in the other dictionary. So in this case, I just want to display {armani: robo} as jeans was already in both. So like the value of jeans in the second dictionary then becomes the main value in the new final dictionary
This is the code:
{k:v for k,v in a.items() if v in b.items()}
But it doesn't work and I don't know how to do the check to see if the value is the key in another list
This should work:
{k:b[v] for k,v in a.items() if v in b}
You were just missing two elements:
You don't need to write if v in b.items() because Python interprets if v in b as "if v is in the keys of b".
You need to map k not to v itself, but to v's value in b, which is b[v].
Alternatively, you could filter with set intersection.
a = {'armani': 'jeans', 'dolce': 'gabbana'}
b = {'jeans': 'robo', 'jobs': 'versace'}
c = set(a.values()).intersection(b)
d = {k:b[k] for k in c}
# or as a one-liner
e = {k:b[k] for k in set(a.values()).intersection(b)}
It might be faster than looping through the whole dictionary.
I think you need:
a = {"armani": "jeans", "dolce": "gabbana"}
b = {"jeans": "robo", "jobs": "versace"}
res = {k1:v2 for k1,v1 in a.items() for k2,v2 in b.items() if v1 ==k2}
print(res)
Output:
{'armani': 'robo'}

Extract all single {key:value} pairs from dictionary

I have a dictionary which maps some keys to 1 or more values.
In order to map to more than 1 value, I'm mapping each individual key to a list. How can I get the number of the single pairs? Is there a quick pythonic way to do this?
My dict looks something like this:
>>print dict
{'key1':['value11',value12, ...], 'key2': ['value21'], 'key3':['value31', 'value32']}
So in the above example, I would expect my output to be 1
With d being the dictionary:
sum(len(v) == 1 for v in d.values())
Or:
map(len, d.values()).count(1)
(The latter requires list around the map if you're using Python 3.)
You could try something like
len([_ for v in d.values() if len(v) == 1])
where d is the name of your dictionary (you should avoid using identifiers such as dict, incidentally).
Depending on your interpreter version, you might need to use itervalues instead of values.
You can use #MosesKoledoye's solution for the short (and probably a tiny bit faster) solution, or this naive version:
print(len([value for value in d.values()
if hasattr(value, '__len__') and len(value) == 1]))
Iterate through values in dictionary and count:
count = 0
for value in dic.values():
if len(value) == 1:
count += 1
print count
You could just filter your dictionary out like this:
data = {
'key1': ['value11', 'value12'],
'key2': ['value21'],
'key3': ['value31', 'value32']
}
result = filter(lambda (k, v): len(v) == 1, data.iteritems())
print result, "=>", len(result)

Python Merge 2 Dictionaries without overwriting

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

Categories