Comparing the strings in key and value of the same dictionary - python

I am looking to solve a problem to compare the string of the key and value of the same dictionary.
To return a dictionary of all key and values where the value contains the key name as a substring.
a = {"ant":"antler", "bi":"bicycle", "cat":"animal"}
the code needs to return the result:
b = {"ant":"antler", "bi":"bi cycle"}

You can iterate through the dictionary and unpack the key and the value at the same time this way:
b = {}
for key, value in a.items():
if value in key:
b[value] = key
This will generate your wanted solution. It does that by unpacking both the key and the value and checking if they match afterward.
You can also shorten that code by using a dictionary comprehension:
b = {key:value for key, value in a.items() if key in value}
This short line does the exact same thing as the code before. It even uses the same functionalities with only one addition - a dictionary comprehension. That allows you to put all that code in one simple line and declare the dictionary on the go.

answer = {k:v for k,v in a.items() if k in v}
Notes:
to iterate over key: value pair we use dict.items();
to check if a string is inside some other string we use in operator;
to filter items we use if-clause in the dictionary comprehension.
See also:
about dictionary comprehensions
about operators in and not in

Related

filter a dictionary by key less than some range of values

I have a dictionary like this,
d = {1:'a', 2:'b', 3:'c', 4:'d'}
Now I want to filter the dictionary where the key should be more than 1 and less than 4 so the dictionary will be,
d = {2:'b', 3:'c'}
I could do this using a for loop, iterating over all the keys. but the execution time will be more looking for some fastest way to do this more efficiently in pythonic way.
you can try below code:
d = {k:v for k,v in d.items() if 1<k<4}
Pythonic way would be to use a dictionary comprehension:
{key: value for key, value in d.items() if 1 < key < 4}
It's readable enough: for each key and value in the items of the dictionary, keep those key: value pairs that have their keys between 1 and 4.
More pythonic way would be a dictionary comprehension
d = {k: v for (k, v) in d.items() if k > 1 and k < 4}
If the efficiency is a bottleneck, you may want to try to use some tree based structure instead of a dictionary that is hash based.
Python dictionaries use hashes of their keys to efficiently lookup and store data. Unfortunately, that means that they don't allow you use the numeric properties of those keys to select data (the way you might be able to do using a slice to index a list).
So I think the best way to do what you want is probably just a dictionary comprehension that tests each key against your boundary values:
d = {key: value for key, value in d.items() if 1 < key < 4}

How to append a value to a not yet existing key?

I have a dictionary like this:
dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
I need to remove duplicate values from the lists. I wrote a function to do this:
no_dups = {}
for keys in dct:
if isinstance(dct[keys], list) and keys != 'dontCareAboutThisKey':
for value in dct[keys]:
if value not in no_dups.values():
no_dups[keys].append(value)
else:
no_dups[keys] = dct[keys]
I'm checking if value of the current key is a list. If no, it just 'copy' key to no_dups dictionary. If it is a list and not a key that I don't care about (there are no duplicates for sure) - it should check if current value already exists in no_dups.values() and append it to current key. Problem is that I'm getting an error:
KeyError: 'two:'
I know it's because I'm trying to add a value to non existing key but I have no idea how to deal with this and make it work.
I think the best way to deal with adding the key and appending at the same time is with dicts' setdefault() method:
no_dups.setdefault(keys,[]).append(value)
But rather than that, you can do this in a more neat way like this:
#remove duplicates
no_dups = {k:list(set(v)) if isinstance(v, list) and k != 'dontCareAboutThisKey' else v
for k,v in dct.items()} # or dct.iteritems() if using python2.x
That hack will, for key value combinations that pass the if test, convert the list into a set (removing duplicates) and then in a list again. For other key value combinations it will leave it intact.
dct = {'one': 'value',
'two': ['value1','value2','value1'],
'three':['otherValue1','otherValue2','otherValue1'],
'dontCareAboutThisKey':'debug'}
set(dct) returns a set, which is a list without duplicates:
for key, value in dct.items():
if not isinstance(value, basestring):
dct[key] = set(value)
If you need a new dictionary you could do:
new_dct = {}
for key, value in dct.items():
if not isinstance(value, basestring):
new_dct[key] = set(value)
else:
new_dct[key] = value
If You want to remove duplicates, just change You list to set, with set() function:
https://docs.python.org/2/tutorial/datastructures.html#sets
It automatically gives You unique set, then You can always change it back to list.

How to check if a key/value is repeated elsewhere in a dictionary using Python

I have a dictionary in python like:
dict = {'dog':['milo','otis','laurel','hardy'],
'cat':['bob','joe'],
'milo':['otis','laurel','hardy','dog'],
'hardy':['dog'],'bob':['joe','cat']}
...and I want to identify if a key exists elsewhere in a dictionary (in some other list of values). There are other questions I could find that want to know if an item simply exists in the dictionary, but this is not my question. The same goes for items in each list of values, to identify items that do not exist in OTHER keys and their associated values in the dictionary.
In the above example, the idea is that dogs and cats are not equal, their keys/values have nothing in common with those that come from cats. Ideally, a second dictionary would be created that collects all of those associated with each unique cluster:
unique.dict = {'cluster1':['dog','milo','otis','laurel','hardy'],
'cluster2':['cat','bob','joe'] }
This is a follow up question to In Python, count unique key/value pairs in a dictionary
It appears that the relationship is symmetric, but your data is not (e.g. there is no key 'otis'). The first part involves making it symmetric, so it won't matter where we start.
(If your data actually is symmetric, then skip that part.)
Python 2.7
from collections import defaultdict
data = {'dog':['milo','otis','laurel','hardy'],'cat':['bob','joe'],'milo':['otis','laurel','hardy','dog'],'hardy':['dog'],'bob':['joe','cat']}
# create symmetric version of data
d = defaultdict(list)
for key, values in data.iteritems():
for value in values:
d[key].append(value)
d[value].append(key)
visited = set()
def connected(key):
result = []
def connected(key):
if key not in visited:
visited.add(key)
result.append(key)
map(connected, d[key])
connected(key)
return result
print [connected(key) for key in d if key not in visited]
Python 3.3
from collections import defaultdict
data = {'dog':['milo','otis','laurel','hardy'],'cat':['bob','joe'],'milo':['otis','laurel','hardy','dog'],'hardy':['dog'],'bob':['joe','cat']}
# create symmetric version of data
d = defaultdict(list)
for key, values in data.items():
for value in values:
d[key].append(value)
d[value].append(key)
visited = set()
def connected(key):
visited.add(key)
yield key
for value in d[key]:
if key not in visited:
yield from connected(value)
print([list(connected(key)) for key in d if key not in visited])
Result
[['otis', 'milo', 'laurel', 'dog', 'hardy'], ['cat', 'bob', 'joe']]
Performance
O(n), where n is the total number of keys and values in data (in your case, 17 if I count correctly).
I'm taking "in some other list of values" literally, to mean that a key existing in its own set of values is OK. If not, that would make things slightly simpler, but you should be able to adjust the code yourself, so I won't write it both ways.
If you insist on using this data structure, you have to do it by brute force:
def does_key_exist_in_other_value(d, key):
for k, v in d.items():
if k != key and key in v:
return True
You could of course condense that into a one-liner with a genexpr and any:
return any(key in v for k, v in d.items() if k != key)
But a smarter thing to do would be to use a better data structure. At the very least use sets instead of lists as your values (which wouldn't simplify your code, but would make it a lot faster—if you have K keys and V total elements across your values, it would run in O(K) instead of O(KV).
But really, if you want to look things up, build a dict to look things up in:
inv_d = defaultdict(set)
for key, value in d.items():
for v in value:
inv_d[v].add(key)
And now, your code is just:
def does_key_exist_in_other_value(inv_d, key):
return inv_d[key] != {key}

index python dictionary by value [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Inverse dictionary lookup - Python
Is there a built in way to index a dictionary by value in Python.
e.g. something like:
dict = {'fruit':'apple','colour':'blue','meat':'beef'}
print key where dict[key] == 'apple'
or:
dict = {'fruit':['apple', 'banana'], 'colour':'blue'}
print key where 'apple' in dict[key]
or do I have to manually loop it?
You could use a list comprehension:
my_dict = {'fruit':'apple','colour':'blue','meat':'beef'}
print [key for key, value in my_dict.items() if value == 'apple']
The code above is doing almost exactly what said you want:
print key where dict[key] == 'apple'
The list comprehension is going through all the key, value pairs given by your dictionary's items method, and making a new list of all the keys where the value is 'apple'.
As Niklas pointed out, this does not work when your values could potentially be lists. You have to be careful about just using in in this case since 'apple' in 'pineapple' == True. So, sticking with a list comprehension approach requires some type checking. So, you could use a helper function like:
def equals_or_in(target, value):
"""Returns True if the target string equals the value string or,
is in the value (if the value is not a string).
"""
if isinstance(target, str):
return target == value
else:
return target in value
Then, the list comprehension below would work:
my_dict = {'fruit':['apple', 'banana'], 'colour':'blue'}
print [key for key, value in my_dict.items() if equals_or_in('apple', value)]
You'll have to manually loop it, but if you'll need the lookup repeatedly this is a handy trick:
d1 = {'fruit':'apple','colour':'blue','meat':'beef'}
d1_rev = dict((v, k) for k, v in d1.items())
You can then use the reverse dictionary like this:
>>> d1_rev['blue']
'colour'
>>> d1_rev['beef']
'meat'
Your requirements are more complex than you realize:
You need to handle both list values and plain values
You don't actually need to get back a key, but a list of keys
You could solve this in two steps:
normalize the dict so that every value is a list (every plain value becomes a single-element)
build a reverse dictionary
The following functions will solve this:
from collections import defaultdict
def normalize(d):
return { k:(v if isinstance(v, list) else [v]) for k,v in d.items() }
def build_reverse_dict(d):
res = defaultdict(list)
for k,values in normalize(d).items():
for x in values:
res[x].append(k)
return dict(res)
To be used like this:
>>> build_reverse_dict({'fruit':'apple','colour':'blue','meat':'beef'})
{'blue': ['colour'], 'apple': ['fruit'], 'beef': ['meat']}
>>> build_reverse_dict({'fruit':['apple', 'banana'], 'colour':'blue'})
{'blue': ['colour'], 'apple': ['fruit'], 'banana': ['fruit']}
>>> build_reverse_dict({'a':'duplicate', 'b':['duplicate']})
{'duplicate': ['a', 'b']}
So you just build up the reverse dictionary once and then lookup by value and get back a list of keys.

how to delete a key from a dictionary with the highest value?

I have a simple question (or so I thought).
I have a dictionary, lets say it looks like this:
dict = {'A':100, 'a':10, 'T':50, 't':5}
I simply want to delete the key with the highest value. I tried this:
del max(dict.values())
and this is the error message: 'Syntax Error: can´t delete function call'.
I want the end result to be:
dict = {'a':10, 'T':50, 't':5}
You need to get a hold of the key to the max value.
Try this instead:
del d[max(d, key=d.get)]
Also, you should avoid calling your variable dict because it shadows the built-in name.
max(d.values()) will give you the maximum value (100), but to delete an entry from a dictionary you need the corresponding key ('A').
You can do this:
d = {'A':100, 'a':10, 'T':50, 't':5}
key_to_delete = max(d, key=lambda k: d[k])
del d[key_to_delete]
By the way, you shouldn't name your dictionary dict because that's the name of a built-in type.
If there may be multiple entries with the same maximum value and you want to delete all of them:
val_to_delete = max(d.values())
keys_to_delete = [k for k,v in d.iteritems() if v==val_to_delete]
for k in keys_to_delete:
del d[k]

Categories

Resources