Python algorithm to search keys and values
Question:
Part of an algorithm course I am taking is to use look through a dictionary of keys and values and continue to look for matching keys & values. For example if there is a matching key, use the value to look up the next key and continue down the rabbit hole. If a match if found more than once to prevent an infinite loop return False else it should return the last key found.
- Look up a key called "bat", and find a value "pig" then continue
- Look up a key called "pig", and find "cat" then continue
- Look up a key called "cat", and find "dog" then continue
- Look up a key called "dog", and find "ant" then continue
- Look up a key called "ant", and find no associated value, and so it
would return "ant"
This is the data:
d = {'bat': 'pig', 'pig': 'cat', 'cat': 'dog', 'dog': 'ant', 'cow': 'bee', 'bee': 'elk', 'elk': 'fly', 'ewe': 'cod', 'cod': 'hen', 'hog': 'fox', 'fox': 'jay', 'jay': 'doe', 'rat': 'ram', 'ram': 'rat'}
This is my function below where I am trying learn recursion…and understand why my function doesn’t return False
when a key saved to MEMORY
has a value greater than 2.
def rabbit_hole(dictionry,key,MEMORY={}):
#print(MEMORY)
if key in MEMORY:
MEMORY[key] += 1
else:
MEMORY[key] = 1
for val in MEMORY.values():
#print(val)
if val == 2:
return False # <--- why not working?
for k,v in dictionry.items():
if k == key:
# recursive call
rabbit_hole(dictionry,v,MEMORY)
#print("return last added dict key")
return list(MEMORY)[-1]
Any tips appreciated not a lot of wisdom here…if I run:
print(rabbit_hole(d, "bat"))
print(rabbit_hole(d, "ewe"))
print(rabbit_hole(d, "jay"))
print(rabbit_hole(d, "yak"))
print(rabbit_hole(d, "rat"))
The code above returns:
ant
hen
doe
yak
ram
But its supposed to return a False
on rat
like this:
ant
hen
doe
yak
False
Answers:
You are close, this point can help you:
-
Your condition to break out of the recursive loop should normally
come first, which is if the key is in MEMORY
-
You need to return the value of the recursive call thanks Abhinav
In addition, some style/optimisation suggestions:
-
If you want to keep track of what you have seen so far, you can use a
set
over a dict
-
Then with a dictionary, you dont need to loop over the keys (that
defeats the point of a dictionary). You can just see if a key is in
the dictionary, and if it is, get the value.
-
Replace the default mutable argument dict
with None, and then set it as a dictionary (or set) if it is passed in as None. This is because if you re-run the function:
print(rabbit_hole(d, "bat"))
print(rabbit_hole(d, "bat"))
It will reuse the same dictionary/set which will then have preexisting keys, rather than creating a new dictionary
ant
False
I would suggest you try again with these points, but if not here is a solution:
def rabbit_hole(dictionary, key, seen=None):
if seen is None:
seen = set()
if key in seen:
return False
seen.add(key)
if key in dictionary:
return rabbit_hole(dictionary, dictionary[key], seen)
else:
return key
The main issue is, you’re not returning the value from the recursive call. As a result, the function returns the last value from the memory list.
This simple fix should return the correct value:
for k,v in dictionry.items():
if k == key:
# recursive call
return rabbit_hole(dictionry,v,MEMORY)
Part of an algorithm course I am taking is to use look through a dictionary of keys and values and continue to look for matching keys & values. For example if there is a matching key, use the value to look up the next key and continue down the rabbit hole. If a match if found more than once to prevent an infinite loop return False else it should return the last key found.
- Look up a key called "bat", and find a value "pig" then continue
- Look up a key called "pig", and find "cat" then continue
- Look up a key called "cat", and find "dog" then continue
- Look up a key called "dog", and find "ant" then continue
- Look up a key called "ant", and find no associated value, and so it
would return "ant"
This is the data:
d = {'bat': 'pig', 'pig': 'cat', 'cat': 'dog', 'dog': 'ant', 'cow': 'bee', 'bee': 'elk', 'elk': 'fly', 'ewe': 'cod', 'cod': 'hen', 'hog': 'fox', 'fox': 'jay', 'jay': 'doe', 'rat': 'ram', 'ram': 'rat'}
This is my function below where I am trying learn recursion…and understand why my function doesn’t return False
when a key saved to MEMORY
has a value greater than 2.
def rabbit_hole(dictionry,key,MEMORY={}):
#print(MEMORY)
if key in MEMORY:
MEMORY[key] += 1
else:
MEMORY[key] = 1
for val in MEMORY.values():
#print(val)
if val == 2:
return False # <--- why not working?
for k,v in dictionry.items():
if k == key:
# recursive call
rabbit_hole(dictionry,v,MEMORY)
#print("return last added dict key")
return list(MEMORY)[-1]
Any tips appreciated not a lot of wisdom here…if I run:
print(rabbit_hole(d, "bat"))
print(rabbit_hole(d, "ewe"))
print(rabbit_hole(d, "jay"))
print(rabbit_hole(d, "yak"))
print(rabbit_hole(d, "rat"))
The code above returns:
ant
hen
doe
yak
ram
But its supposed to return a False
on rat
like this:
ant
hen
doe
yak
False
You are close, this point can help you:
-
Your condition to break out of the recursive loop should normally
come first, which is if the key is in MEMORY -
You need to return the value of the recursive call thanks Abhinav
In addition, some style/optimisation suggestions:
-
If you want to keep track of what you have seen so far, you can use a
set
over adict
-
Then with a dictionary, you dont need to loop over the keys (that
defeats the point of a dictionary). You can just see if a key is in
the dictionary, and if it is, get the value. -
Replace the default mutable argument
dict
with None, and then set it as a dictionary (or set) if it is passed in as None. This is because if you re-run the function:
print(rabbit_hole(d, "bat"))
print(rabbit_hole(d, "bat"))
It will reuse the same dictionary/set which will then have preexisting keys, rather than creating a new dictionary
ant
False
I would suggest you try again with these points, but if not here is a solution:
def rabbit_hole(dictionary, key, seen=None): if seen is None: seen = set() if key in seen: return False seen.add(key) if key in dictionary: return rabbit_hole(dictionary, dictionary[key], seen) else: return key
The main issue is, you’re not returning the value from the recursive call. As a result, the function returns the last value from the memory list.
This simple fix should return the correct value:
for k,v in dictionry.items():
if k == key:
# recursive call
return rabbit_hole(dictionry,v,MEMORY)