I have a dictionary which has peoples' first names as keys. Each name has a capitalised first letter (James, Ben, John, etc).
I use list comprehension to check if any keys are in a string:
[val for key, val in name_dict.items() if key in new_message]
The issue is that sometimes the names appear in new_message without capitalised first letters (james, ben, john, etc). I could add these variations to the dictionary but that sould invovle a lot of work.
Is there a simple way to iterate over the dictionary keys in a case insensitive way?
Use title() on new_message, it will capitalize all the words in the string
new_message = 'James, ben, JOHN'
print(new_message.title()) # James, Ben, John
You can just lower the text while iterating,
new_message = [x.lower() for x in new_message]
[val for key, val in name_dict.items() if key.lower() in new_message]
( Assuming if the new_message is list, for string it will be just new_message.lower() )
This will make the comparison case-insensitive.
Full example
>>> new_message = ['John', 'JameS', 'BEN']
>>> name_dict = {'john': 1, 'Ben': 2, 'JaMES': 3}
>>>
>>> [x.lower() for x in new_message]
['john', 'james', 'ben']
>>> new_message = [x.lower() for x in new_message]
>>> [val for key, val in name_dict.items() if key.lower() in new_message]
[1, 2, 3]
>>>
Related
I have a list1 with names:
["SAM","TOM","LOUIS"]
And I have a dict1 like this (where in the list of values there are no repeated names:
{"NICE": ["SAM", "MAIK", "CARL", "LAURA", "MARTH"],
"BAD": ["LOUIS", "TOM", "KEVIN"],
"GOOD": ["BILL", "JEN", "ALEX"]}
How could I iterate throught the list1 so that if any of the names appear in any of the lists of the dict1 it assigns the corresponding key of the dict?
I am looking forward to generate the following output:
["NICE","BAD","BAD"]
which would correspond to the keys of the values that appear in the list : SAM, TOM , LOUIS .
This is what I thought about:
lista=[]
for k,v in dict1:
for values in arr1:
if values in v:
lista.append(v)
lista
However not sure how to iterate over the different v, how can I get the desired output in an efficient manner?
You can create an intermediate dict that maps names to their keys in dict1:
categories = {name: category for category, names in dict1.items() for name in names}
so that you can map the names in list1 to their respective keys efficiently with:
[categories[name] for name in list1]
which returns:
['NICE', 'BAD', 'BAD']
I think you need the items() function for dictionaries here. For each name, iterate over all of the dictionary pairs and stop when a match is found, adding the corresponding adjective to your list.
lista = []
for name in list1:
for adjective, names in dict1.items():
if name in names:
lista.append(adjective)
break
return lista
There are 2 ways to achieve your result.
The way you intended was to use dict1.items(). Unfortunately, that way is computationally slow, so for the sake of completeness I'll add the the more efficient way:
# First, convert the dict to a different representation:
from itertools import chain, repeat
# Change {k: [v1,v2], k2: [v3,v4]} to {v1: k, v2: k, v3: k2, v4: k2}
name_to_adjective = dict(chain.from_iterable(zip(v, repeat(k)) for k, v in a.items()))
Name_to_adjective is now equal to this:
{'ALEX': 'GOOD',
'BILL': 'GOOD',
'CARL': 'NICE',
'JEN': 'GOOD',
'KEVIN': 'BAD',
'LAURA': 'NICE',
'LOUIS': 'BAD',
'MAIK': 'NICE',
'MARTH': 'NICE',
'SAM': 'NICE',
'TOM': 'BAD'}
Then, you can get your result in one run:
result = [name_to_adjective[name] for name in list1]
I believe the following will give you your desired output:
L = ["SAM","TOM","LOUIS"]
D = {"NICE": ["SAM", "MAIK", "CARL", "LAURA", "MARTH"]
, "BAD": ["LOUIS", "TOM", "KEVIN"]
, "GOOD": ["BILL", "JEN", "ALEX"]}
lista = []
for key in D.keys():
for name in L:
if name in D[key]:
lista.append(key)
print(lista)
The D.keys() part gives you a list of the keys in a friendly manner (e.g, ["NICE", "BAD", "GOOD"]).
You iterate over this and then look for each name from L (in order) in the dictionary.
This is not the most efficient way to do this, however, it's a more straightforward approach.
I want to make a function called remove_short_synonyms() which is passed a dict
as a parameter. The keys of the parameter dict are words and the
corresponding values are lists of synonyms. The function removes all the
synonyms which have less than 7 characters from each corresponding list
of synonyms.
If this is the dict:
synonyms_dict = {'beautiful': ['pretty', 'lovely', 'handsome', 'dazzling', 'splendid', 'magnificent']}
How can I get this as the output?
{'beautiful': ['dazzling', 'handsome', 'magnificent', 'splendid']}
I think your question is more proper to be titled as Remove values from a list instead of dict.
You can use remove, del or pop to remove element in a python list.
Difference between del, remove and pop on lists
Or in a more pythonic way, i think, is
dict['beautiful'] = [item for item in dict['beautiful'] if len(item)>=7]
Make use of dict comprehension and list comprehension.
synonyms_dict = {'beautiful' : ['pretty', 'lovely', 'handsome', 'dazzling', 'splendid', 'magnificent']}
synonyms_dict = {k:[v1 for v1 in v if len(v1) >= 7] for k, v in synonyms_dict.items()}
print(synonyms_dict)
# {'beautiful': ['handsome', 'dazzling', 'splendid', 'magnificent']}
Assuming you have python>=3.x, a more readable solution for a beginner would be:
synonyms_dict = {'beautiful' : ['pretty', 'lovely', 'handsome', 'dazzling', 'splendid', 'magnificent']}
new_list = []
for key,value in synonyms_dict.items():
for i in range(len(value)):
if len(value[i]) >= 7:
new_list.append(value[i])
synonyms_dict['beautiful'] = new_list
print(synonyms_dict)
Here's a function that modifies the existing dictionary rather than replacing it. This can be useful if you have multiple references to the same dictionary.
synonyms_dict = {
'beautiful' : ['pretty', 'lovely', 'handsome', 'dazzling', 'splendid', 'magnificent']
}
def remove_short_synonyms(d, minlen=7):
for k, v in d.items():
d[k] = [word for word in v if len(word) >= minlen]
remove_short_synonyms(synonyms_dict)
print(synonyms_dict)
output
{'beautiful': ['handsome', 'dazzling', 'splendid', 'magnificent']}
Note that this code does replace the existing lists in the dictionary with new lists. You could keep the old list objects, if you really need to do that, by changing the assignment line to
d[k][:] = [word for word in v if len(word) >= minlen]
although that will be slightly slower, and there's probably no reason to do this.
def remove_short_synonyms(self, **kwargs):
dict = {}
word_list = []
for key, value in synonyms_dict.items():
for v in value:
if len(v) > 7:
word_list.append(v)
dict[key] = word_list
print dict
remove_short_synonyms(synonyms_dict)
I have the following string "first: 1\r\nsecond: 2\r\n", I want to receive following dict {'first': 1, 'second': 2}.
How can I do that?
You can use regular expressions:
import re
matches = re.findall(r'(\w+):\s*(\d+)', my_string)
# [('first', '1'), ('second', '2')]
matches = [(x[0], int(x[1])) for x in matches]
# [('first', 1), ('second', 2)]
d = dict(matches)
# {'first': 1, 'second': 2}
If you can guarantee that there is a space between the colon and the value, split by newlines, then split by whitespace, then convert to integer, then make a dictionary out of the result:
s = 'first: 1\r\nsecond: 2\r\n'
result = {k:int(v) for k,v in (item.split() for item in s.strip().split('\r\n'))}
Result:
>>> result
{'first:': 1, 'second:': 2}
If you're not guaranteed to have whitespace between the colon and the value, but you know that it's always a string not containing a colon for the key and an integer for the value, you could try a regular expression:
import re
s = 'first: 1\r\nsecond:2\r\n'
result = {k.strip():int(v) for k,v in re.findall(r'([^:]+):\s*(\d+)', s)}
Result:
>>> result
{'first': 1, 'second': 2}
You could use the split method with a for loop, though I doubt it's the most efficient way to do it :
def strToDict(string):
myDict = {}
for line in string.strip().split("\r\n"):
key, val = map(str.strip, line.split(": "))
myDict[key] = int(val)
return myDict
strToDict("first: 1\r\nsecond: 2\r\n") # {'first': 1, 'second': 2}
I have a dictionary with key-value pair. My value contains strings. How can I search if a specific string exists in the dictionary and return the key that correspond to the key that contains the value.
Let's say I want to search if the string 'Mary' exists in the dictionary value and get the key that contains it. This is what I tried but obviously it doesn't work that way.
#Just an example how the dictionary may look like
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}
#Checking if string 'Mary' exists in dictionary value
print 'Mary' in myDict.values()
Is there a better way to do this since I may want to look for a substring of the value stored ('Mary' is a substring of the value 'Mary-Ann').
You can do it like this:
#Just an example how the dictionary may look like
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}
def search(values, searchFor):
for k in values:
for v in values[k]:
if searchFor in v:
return k
return None
#Checking if string 'Mary' exists in dictionary value
print search(myDict, 'Mary') #prints firstName
I am a bit late, but another way is to use list comprehension and the any function, that takes an iterable and returns True whenever one element is True :
# Checking if string 'Mary' exists in the lists of the dictionary values
print any(any('Mary' in s for s in subList) for subList in myDict.values())
If you wanna count the number of element that have "Mary" in them, you can use sum():
# Number of sublists containing 'Mary'
print sum(any('Mary' in s for s in subList) for subList in myDict.values())
# Number of strings containing 'Mary'
print sum(sum('Mary' in s for s in subList) for subList in myDict.values())
From these methods, we can easily make functions to check which are the keys or values matching.
To get the keys containing 'Mary':
def matchingKeys(dictionary, searchString):
return [key for key,val in dictionary.items() if any(searchString in s for s in val)]
To get the sublists:
def matchingValues(dictionary, searchString):
return [val for val in dictionary.values() if any(searchString in s for s in val)]
To get the strings:
def matchingValues(dictionary, searchString):
return [s for s i for val in dictionary.values() if any(searchString in s for s in val)]
To get both:
def matchingElements(dictionary, searchString):
return {key:val for key,val in dictionary.items() if any(searchString in s for s in val)}
And if you want to get only the strings containing "Mary", you can do a double list comprehension :
def matchingStrings(dictionary, searchString):
return [s for val in dictionary.values() for s in val if searchString in s]
Klaus solution has less overhead, on the other hand this one may be more readable
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}
def search(myDict, lookup):
for key, value in myDict.items():
for v in value:
if lookup in v:
return key
search(myDict, 'Mary')
import re
for i in range(len(myDict.values())):
for j in range(len(myDict.values()[i])):
match=re.search(r'Mary', myDict.values()[i][j])
if match:
print match.group() #Mary
print myDict.keys()[i] #firstName
print myDict.values()[i][j] #Mary-Ann
>>> myDict
{'lastName': ['Stone', 'Lee'], 'age': ['12'], 'firstName': ['Alan', 'Mary-Ann'],
'address': ['34 Main Street, 212 First Avenue']}
>>> Set = set()
>>> not ['' for Key, Values in myDict.items() for Value in Values if 'Mary' in Value and Set.add(Key)] and list(Set)
['firstName']
For me, this also worked:
def search(myDict, search1):
search.a=[]
for key, value in myDict.items():
if search1 in value:
search.a.append(key)
search(myDict, 'anyName')
print(search.a)
search.a makes the list a globally available
if a match of the substring is found in any value, the key of that
value will be appended to a
Following is one liner for accepted answer ... (for one line lovers ..)
def search_dict(my_dict,searchFor):
s_val = [[ k if searchFor in v else None for v in my_dict[k]] for k in my_dict]
return s_val
To provide a more general solution for others using this post to do similar or more complex python dictionary searches: you can use dictpy
import dictpy
myDict = {'age': ['12'], 'address': ['34 Main Street, 212 First Avenue'],
'firstName': ['Alan', 'Mary-Ann'], 'lastName': ['Stone', 'Lee']}
search = dictpy.DictSearch(data=myDict, target='Mary-Ann')
print(search.result) # prints -> [firstName.1, 'Mary-Ann']
The first entry in the list is the target location: dictionary key "firstName" and position 1 in the list. The second entry is the search return object.
The benefit of dictpy is it can find multiple 'Mary-Ann' and not just the first one. It tells you the location in which it found it, and you can search more complex dictionaries (more levels of nesting) and change what the return object is.
import re
for i in range(len(myDict.values())):
for j in range(len(myDict.values()[i])):
match=re.search(r'Mary', myDict.values()[i][j])
if match:
print match.group() #Mary
print myDict.keys()[i] #firstName
print myDict.values()[i][j] #Mary-Ann
def search(myDict, lookup):
a=[]
for key, value in myDict.items():
for v in value:
if lookup in v:
a.append(key)
a=list(set(a))
return a
if the research involves more keys maybe you should create a list with all the keys
import json
'mtach' in json.dumps(myDict)
is true if found
I have a list of strings. I am willing to create a dictionary which its keys are all the strings in the list (each string is a key of course).
Now for the values: The value corresponding to each key will be the string which comes next after the key string on the list. The values will be from list type.
Remarks: The last word won't be included in the dictionary.
a key won't appear twice on the dic. if there are more than one values for a certain key, they will be added to the exist value's list of the key.
The order doesn't matter (the dictionary can be not sorted if it makes the job easier).
Example:
for the list:
List = ['today','is','worm','and','dry']
the dictionary will be:
Dic={'today': ['is'], 'is': ['worm'],'worm': ['and'], 'and':['dry']}
Thanks,
l = ['today','is','worm','and','dry']
d = {}
for w1, w2 in zip(l, l[1:]):
d.setdefault(w1, []).append(w2)
# d == {'and': ['dry'], 'is': ['worm'], 'today': ['is'], 'worm': ['and']}
Not very fine but it is working
>>> List = ['today','is','worm','and','dry']
>>> Dic ={}
>>> key = None
>>> for item in List:
... if key:
... Dic.update({key:item})
... key=item
...
>>> Dic
{'and': 'dry', 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>>
(based on #eumiro's answer)
>>> l = ['today','is','worm','and','dry']
>>> print dict(zip(l, l[1:]))
{'and': 'dry', 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>> print dict(zip(l, l[1:] + [None]))
{'and': 'dry', 'dry': None, 'is': 'worm', 'worm': 'and', 'today': 'is'}
>>> print dict((k, [v]) for (k, v) in zip(l, l[1:] + [None]))
{'and': ['dry'], 'dry': [None], 'is': ['worm'], 'worm': ['and'], 'today': ['is']}
Try this:
lst = ['today','is','worm','and','dry']
dic = {}
for k in xrange(len(lst) - 1):
dic[lst[k]] = [lst[k+1]]
It's an efficient answer, since it doesn't create any additional lists for building the dictionary. You can check the result, it's what was expected:
dic == {'today': ['is'], 'is': ['worm'],'worm': ['and'], 'and':['dry']}
> True
You can achieve it by the following code:
Dic = dict((key, [item]) for key, item in zip(List, List[1:]))
and the result will be the following:
>>> Dic
{'and': ['dry'], 'is': ['worm'], 'worm': ['and'], 'today': ['is']}
If you need more performant solution, you can use izip() function:
from itertools import izip
Dic = dict((key, [item]) for key, item in izip(List, List[1:]))
which will give the same result, but in a more efficient way.
But please follow naming conventions for Python (eg. call your variables my_dict and my_list, but preferably give them more meaningful names) and do not overwrite list and dict keywords (that is in case you would like to give your variables such names).