Search string value from a list with dictionary list values - python

Below I have a list and dict with the values as below. The dict has keys associated with list values.
What I wanted was to search strings in the list with values of the list in the dictionary and with each match capture the corresponding key value and create a new list with the key values for each match as above listed.
list = ['man', 'men', 'boy', 'buoy', 'cat','caat']
dict={'man':['man', 'men', 'mun'], 'boy':['boy','buoy','bay'], 'cat':['cat','caat','cut']}
Expected output for above case is:
Outputlist=['man','man','boy','boy','cat','cat']
When I tried the same I am getting only one item to match as below.
lis = ['man', 'men', 'boy', 'buoy', 'cat','caat']
dic={'man':['man', 'men', 'mun'], 'boy':['boy','buoy','bay'], 'cat':['cat','caat','cut']}
for key,value in dic.items():
if value in lis:
output.append(key)
print(output)

you can use a nested list comprehension. Notice that you should not use list and dict as variables:
x = [key for key, value in dict_.items() for x in list_ if x in value]
print(x) # ['man', 'man', 'boy', 'boy', 'cat', 'cat']

The first thing to note is that to achieve the same length input and output lists, you should be looping over the list, not the dictionary.
ys = [k for x in xs for k, v in d.items() if x in v]
Another way is to construct a reverse mapping. This should make things asymptotically faster:
lookup = {x: k for k, v in d.items() for x in v}
>>> lookup
{
'bay': 'boy',
'boy': 'boy',
'buoy': 'boy',
'caat': 'cat',
'cat': 'cat',
'cut': 'cat',
'man': 'man',
'men': 'man',
'mun': 'man',
}
Then, simply:
ys = [lookup[x] for x in xs]

I think you did it the wrong way. First, you wan to go across the lis and after find the corresponding key :
output = []
lis = ['man', 'men', 'boy', 'buoy', 'cat','caat']
dic={'man':['man', 'men', 'mun'], 'boy':['boy','buoy','bay'], 'cat':['cat','caat','cut']}
for l in lis:
for key, value in dic.items():
if l in value:
output.append(key)
print(output)
As the others mention, you can use list comprehension to do it directly:
output = [next(k for k,v in dict if l in v) for l in list]

Related

How to make a dictionary from two nested list?

I have two nested lists:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
and I want to make a dictionary from these lists with keys from list1 and values from list2:
d = {s0:['hello','world','the'],s1:['as','per','the'],s2:['assets','order']}
The output should look like this:
d = {s0:['hello','world','the'],s1:['as','per','the'],s2:['assets','order']}
The following code works if list1 is a normal (non-nested) list. But it doesn't work when list1 is a nested list.
dict(zip(list1, list2))
The problem here is that lists are not hashable, so one thing you can do is to flatten your list with itertools.chain and then build the dictionary with strings (which are immutable) as keys following you're current approach (read here for a more detailed explanation on this topic):
from itertools import chain
dict(zip(chain.from_iterable(list1),list2))
{'s0': ['hello', 'world', 'the'],
's1': ['as', 'per', 'the'],
's2': ['assets', 'order']}
If you want to do it manually (to understand algorithm for exemple), here is a way to do so:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
if len(list1) != len(list2):
exit(-1)
res = {}
for index, content in enumerate(list1):
res[content[0]] = list2[index]
print(res)
Another answer could be :
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
output_dict = {element1[0]: element2 for element1, element2 in zip(list1, list2)}
An similar way of this dict-comprehension :
output_dict = {element1: element2 for [element1], element2 in zip(list1, list2)}
Output :
{'s0': ['hello', 'world', 'the'],
's1': ['as', 'per', 'the'],
's2': ['assets', 'order']}
It's a strange way to store matching information in the first place, but I would combine them like this:
list1 = [['s0'], ['s1'], ['s2']]
list2 = [['hello','world','the'],['as','per','the'],['assets','order']]
assert(len(list1) == len(list2))
output_dict = dict()
for index in range(len(list1)):
output_dict[list1[index][0] = list2[index]
result:
{'s0': ['hello', 'world', 'the'], 's1': ['as', 'per', 'the'], 's2': ['assets', 'order']}
I am assuming that the variables s0, s1 and s2 are meant to be strings like in the first list.

How would I remove words from dictionary key lists that contain 6 or more letters?

I can't figure out how to create a function that is able to remove words with less than 6 characters from each list that is a value of a key of a dictionary.
I'm trying to pop each word that is less than 6 out of the list but I'm getting "TypeError: cannot unpack non-iterable int object". I don't know if the method I am using is correct.
def remove_word(words_dict):
items_list = list(words_dict.items())
for key, value in range(len(items_list) -1, -1, -1):
if len(value) < 6:
items_list.pop()
words_dict = items_list.sort()
return words_dict
words_dict = {'colours' : ['red', 'blue', 'green'],
'places' : ['america', 'china', 'malaysia', 'argentina', 'india'],
'animals' : ['lion', 'cat', 'dog', 'wolf', 'monkey',
'zebra'],
}
Should print:
1.
colours : []
places : ['america', 'malaysia', 'argentina']
animals : ['monkey']
# input data
words_dict = {'colours' : ['red', 'blue', 'green'],
'places' : ['america', 'china', 'malaysia', 'argentina', 'india'],
'animals' : ['lion', 'cat', 'dog', 'wolf', 'monkey',
'zebra'],
}
# creating a final output dictionary
#looping through each key value pair present in dictionary and adding the key
# the final dictionary and processed valeus to the corresponding key
# using lambda function, fast readable and easy to understand
result = {k:list(filter(lambda x:len(x)>=6, v)) for k,v in words_dict.items()}
print(result)
output
{'colours': [], 'places': ['america', 'malaysia', 'argentina'], 'animals': []}
Maybe not the cleanest way, this is not an effective way to do it, but it is readable and I wrote it this way so you can see the logic for it to work
In [23]: def remove_word(my_dict):
...: for key in my_dict:
...: to_delete = []
...: for values in my_dict[key]:
...: if len(values) < 6:
...: to_delete.append(values)
...: for word in to_delete:
...: my_dict[key].remove(word)
...: return my_dict
...:
...:
It will give you the desired output
In [26]: remove_word(words_dict)
Out[26]:
{'colours': [],
'places': ['america', 'malaysia', 'argentina'],
'animals': ['monkey']}
{k: [i for i in v if len(i) > 5] for k, v in words_dict.items()}
You can do this using a loop over the dict and a nested comprehension.
words_dict = {
'colours' : ['red', 'blue', 'green'],
'places' : ['america', 'china', 'malaysia', 'argentina', 'india'],
'animals' : ['lion', 'cat', 'dog', 'wolf', 'monkey','zebra'],
}
for key, lst in words_dict.items():
filtered_lst = [word for word in lst if len(word) >= 6]
print(f"{key} : {filtered_lst}")
Output for this is:
colours : []
places : ['america', 'malaysia', 'argentina']
animals : ['monkey']
Or to actually make a function that essentially removes the elements and returns the corrected dict as your code originally did then use something as follows:
def remove_words(words_dict):
return {key: [word for word in lst if len(word) >= 6]
for key, lst in words_dict.items()}
But then you'd still need to loop over them to print it correctly.
words_dict = remove_words(words_dict)
for key, lst in words_dict.items():
print(f"{key} : {lst}")
You can do this with nested loops:
for key in words_dict:
words_dict[key] = [i for i in dict[key] if len(i) >= 6]
A loop comprehension (building a new list based on criteria from the previous list) is actually the easiest way to accomplish this task, because of how python handles list iterators. You can actually put that inside a dict comprehension as well:
new_words_dict = {key: [i for i in value if len(i) >= 6] for key, value in words_dict.items()}

Merging Dictionary values by key names

I have a dictionary of lists that includes keys with very similar names that I need to merge together; for example,
new_dict = {
'a0':['hello', 'how'],
'a1':['are'],
'a2':['you'],
'b0':['fine'],
'b1':['thanks']
}
And I want something like this:
desired = {
'a':['hello', 'how', 'are', 'you'],
'b':['fine', 'thanks']
}
I though that I could change the key as if it was a list element, like this:
for key in new_dict.keys():
if 'a' in key:
key == 'a'
But this obviously doesn't work. What's the best way to do it? Thanks.
This is one way:
from collections import defaultdict
d = defaultdict(list)
for k, v in new_dict.items():
d[k[0]].extend(v)
# defaultdict(list,
# {'a': ['hello', 'how', 'are', 'you'], 'b': ['fine', 'thanks']})
You can use a defaultdict:
from collections import defaultdict
desired = defaultdict(list)
for key, val in new_dict.items():
desired[key[0]] += val
As pointed out in other comments, defaultdictionary eliminates the need for the if else statements.
new_new_dict={}
for k,v in new_dict.items():
k1 = k[0]
if k1 in new_new_dict:
new_new_dict[k1].extend(v)
else:
new_new_dict[k1]=v
You can use itertools.groubpy:
import itertools
import re
new_dict = {
'a0':['hello', 'how'],
'a1':['are'],
'a2':['you'],
'b0':['fine'],
'b1':['thanks']
}
final_data = {a:[i for b in map(lambda x:x[-1], list(b)) for i in b] for a, b in itertools.groupby(sorted(new_dict.items(), key=lambda x:re.findall('^[a-zA-Z]+', x[0])[0]), key=lambda x:re.findall('^[a-zA-Z]+', x[0])[0])}
Output:
{'a': ['are', 'hello', 'how', 'you'], 'b': ['fine', 'thanks']}

Saving first letter of word as a key, and associated words as values?

How would I take the first letter of each word and save it as a key in a dictionary with associated words?
list = ['pine', 'dinner', 'liver', 'love', 'pick']
Output:
dictionary = {'p' : ['pine', 'pick'], 'd' : ['dinner'], 'l' : ['love', 'liver']}
Using default Dict we can do it simply:
from collections import defaultdict
list_ = ['pine', 'dinner', 'liver', 'love', 'pick']
x = defaultdict(list)
for item in list_:
x[item[0]].append(item)
print(x)
# defaultdict(<class 'list'>, {'p': ['pine', 'pick'], 'd': ['dinner'], 'l': ['liver', 'love']})
You can then use x like a dictionary:
print(x['p'])
#['pine', 'pick']
Dict = dict()
# iterate over the collection
for word in words:
# get the first letter
letter = word[0]
# the default value for key 'letter'
# will be an empty list
# if the key isn't present yet
# otherwise, nothing's changed
Dict.setdefault(letter, [])
# now you are sure that there's a list at that key
Dict[letter].append(word)
This should do it, I think.
dictionary = {}
list = ['pine', 'dinner', 'liver', 'love', 'pick']
for i in list:
if i[0] not in dictionary.keys():
dictionary[i[0]] = []
dictionary[i[0]].append(i)
Try:
list = ['pine', 'dinner', 'liver', 'love', 'pick']
d= dict()
for item1 in list:
li=[]
for item2 in list:
if item1[0]==item2[0]:
li.append(item2)
d[item1[0]]= li
print d

List of Lists to Dictionary of Lists

I am having a hard time converting a list of lists to a dictionary of lists due to some of the key values being the same, I am also getting an issue with the null value. My List is:
L = [['shark', ['one']], ['shark',['two']], ['fish', ['one']], ['fish', ['two']], ['fish',[]]]
My desired dictionary of lists would be structured like this:
Dic = {'shark': ['one','two'], 'fish':['one', 'two', '0']}
Is there any trick to be able to get the same key values to combine into a dictionary of lists like this?
L = [['shark', ['one']], ['shark',['two']], ['fish', ['one']], ['fish', ['two']], ['fish',[]]]
p = {}
for k, v in L:
d = p.setdefault(k, [])
if not v:v = ['0']
d.extend(v)
print p
output:
{'shark': ['one', 'two'], 'fish': ['one', 'two', '0']}
from collections import defaultdict
dct = defaultdict(list)
l = [['shark', ['one']], ['shark',['two']], ['fish', ['one']], ['fish', ['two']], ['fish',[]]]
for x in l:
dct[x[0]].append(x[1])
dct
>>> defaultdict(list,
{'fish': [['one'], ['two'], []], 'shark': [['one'], ['two']]})
if you need '0' instead of [] then add an if clause to the loop

Categories

Resources