Reputation: 103
Say I have a dictionary with keys being a category name and values being words within that category. For example:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
For any given input I want to create a list with two items where the first item is the value word and the second is the key word. For example, the expected output should be:
input: kitchen
output: ['kitchen','rooms']
input: bee
output: ['bee','insects']
I checked the question Get key by value in dictionary but afaict all answers work for dictionaries with 1 value per key.
I've tried the following naive, closed form code:
word=input('Enter a word: ')
word_pair=[]
word_pair.append(word)
if word in (words['seasons']):
index=0
elif word in (words['rooms']):
index=1
elif word in (words['insects']):
index=2
else:
index=3
try:
key_val=list(words.keys())[index]
word_pair.append(key_val)
except IndexError:
word_pair.append('NA')
print(word_pair)
Obviously, this code only works for this specific dictionary as is. If I wanted to add a category, I'd have to add an elif clause. If I wanted to change the name of a category or their order, remove one, combine two or more, etc., I'd have to tweak a whole bunch of things by hand.
Is there a more generalized way to do this?
All help is appreciated.
Upvotes: 0
Views: 949
Reputation: 24802
Another way to do it would be to transform your input dictionnary to inverse the logic: make values the keys, and the keys, values.
So a solution like that one:
def invert_dic(index):
new_dic = {}
for k,v in index.items():
for x in v:
new_dic.setdefault(x,[]).append(k)
and then you'd do:
index = invert_dic(words) # linear time, O(n)
word = input('Enter a word: ')
categories = index.get(word, ['None'])) # constant time, O(1)
print(', '.join(f"Your word is in those categories: {categories}")
That solution is mimicking the concept of indexes in databases, where you spend time at the creation of the database (the words
dictionary being converted as the index
dictionary) and memory to store that index, to have very fast resolution when looking up a word using the hash algorithm (where looking a key is in constant time).
A bonus of the above solution is that if a word is in two categories, you'll get the list of all the categories your word is in.
Upvotes: 0
Reputation: 7812
You can use generator with unpacking:
inp = input()
result, *_ = ([inp, k] for k, v in words.items() if inp in v)
Even better to use next()
with generator, cause it will stop after first match found:
result = next([inp, k] for k, v in words.items() if inp in v)
Upvotes: 1
Reputation: 104032
You can invert that dict with:
>>> {s_v:k for k,v in words.items() for s_v in v}
{'summer': 'seasons', 'spring': 'seasons', 'autumn': 'seasons', 'winter': 'seasons', 'kitchen': 'rooms', 'loo': 'rooms', 'livingroom': 'rooms', 'hall': 'rooms', 'diningroom': 'rooms', 'bedroom': 'rooms', 'bee': 'insects', 'butterfly': 'insects', 'beetle': 'insects'}
And then lookup your input in the inverted dict.
Upvotes: 1
Reputation: 13079
You would test using in
rather than exact match (see word in value
in the code below), and you'd probably also want to include some kind of check that there is only one matching key, and provided that there is, use the first one.
words = {
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
word = 'kitchen'
keys = [key for key, value in words.items() if word in value]
if len(keys) != 1:
raise ValueError
word_pair = [word, keys[0]]
print(word_pair)
Gives:
['kitchen', 'rooms']
Upvotes: 0
Reputation: 312
You can iterate over the dictionary keys:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
search_text = input("input: ")
for key in words.keys():
if search_text in words[key]:
print("output: {0}".format([search_text,key]))
Upvotes: 0
Reputation: 1177
You can do it like this:
words={
'seasons':('summer','spring','autumn','winter'),
'rooms':('kitchen','loo','livingroom','hall','diningroom','bedroom'),
'insects':('bee','butterfly','beetle')}
def find_cat(word):
for category, items in words.items():
if word in items:
return category
word=input('Enter a word: ')
print(find_cat(word))
Explanation: words.items()
return a tuple (key, value) for each key in the dictionary. In this case, value is a list. So, we can use the in
operator to find if the word
is in that list. If yes, simply return the key.
Upvotes: 0