-1

I wanted to make a function that allows someone to guess the value of any key in the dictionary, and find out if they were right or wrong. If the key exists in the dictionary and that value is the correct value, then the function should return true. In all other cases, it should return false. But it prints out False for every key in the dictionary not just once. Thanks.

WaywardSonDict = {"Artist":"Kansas","Song":"Carry on Wayward Son","Genre":"Hard Rock","Album":"Leftoverture","Writer":"Kerry Livgren"}

def valueDict(key,value):
    for i, j in WaywardSonDict.items():
        if i == key and j == value:
            print(True)
        else:
            print(False)

valueDict("Genre","Hard Rock")
  • 1
    It would be more efficient to check if the key exists then check its value rather than looping over the items in the dictionary. As to why it is printing false it's because your checking every key pair in the dictionary, so there are a bunch that don't match – R. Arctor Aug 06 '21 at 18:23
  • 1
    Are you familiar with `return`? In your own words, what *is* a function, and *why* do you use them? – Karl Knechtel Aug 06 '21 at 18:28

6 Answers6

2

You're printing True/False at every iteration of your loop. Instead, you could return True when there's a match and False at the end of the loop (i.e., when there is no match):

def valueDict(key, value):
    for k in WaywardSonDict:
        if k == key and WaywardSonDict[k] == value:
            return True
    return False

Alternatively, instead of looping over the entire dictionary, you could use .get which returns None if the key doesn't exist in the dictionary:

def valueDict(key, value):
    if WaywardSonDict.get(key)==value:
        return True
    return False
not_speshal
  • 22,093
  • 2
  • 15
  • 30
  • To recap the cleverness: if [`.get`]() returns `None` you don't have to test if the key exists and matches `k == key` before. Benefit: get rid of the for-loop and simplify. Right? – hc_dev Aug 06 '21 at 19:13
  • @hc_dev - Correct! – not_speshal Aug 06 '21 at 19:15
  • The whole point of a dictionary is that you can look up a key without looping over all the keys. _Looping over the entire dictionary_ defeats the purpose of having a dictionary in the first place. Your "alternatively..." should be the _first_ (and IMO only) answer. – Pranav Hosangadi Aug 06 '21 at 19:59
  • @PranavHosangadi - I tried to change OP's original code as little as possible so they could learn where they're going wrong. The "alternative" solution is just to teach them the better way. – not_speshal Aug 06 '21 at 20:17
0

An easy way to do this is to have a boolean variable that is set default to False, and changes to True if you find a match. Then, you just print out the variable at the end:

WaywardSonDict = {"Artist":"Kansas","Song":"Carry on Wayward Son","Genre":"Hard Rock","Album":"Leftoverture","Writer":"Kerry Livgren"}

def valueDict(key,value):
    guessed = False
    for i, j in WaywardSonDict.items():
        if i == key and j == value:
           guessed = True
           break
    print(guessed)
Aniketh Malyala
  • 2,650
  • 1
  • 5
  • 14
  • That __defaulting__ by initializing a finder-variable like `guessed = False` is a useful pattern. And suggested code reduces your multiple boolean print-outs to just a single final result. For each loop, __consider the exit-condition__ (when to stop)! Here: if already found after first iteration, do you really need to search and test further? – hc_dev Aug 06 '21 at 19:09
  • True, I'll just add a break statement – Aniketh Malyala Aug 06 '21 at 19:11
0

Here you go:

WaywardSonDict = {"Artist":"Kansas","Song":"Carry on Wayward Son","Genre":"Hard Rock","Album":"Leftoverture","Writer":"Kerry Livgren"}

def valueDict(key,value):
    if (key,value) in WaywardSonDict.items():
        print('True')
    else:
        print('False')

valueDict("Genre","Hard Rock")

OUTPUT

True
0
def is_in_wayword_son_dict(key, value):
    if WaywordSonDict.get(key, '') == value:
        return True
    return False   

Get the value of key from the dictionary if it exists, compare to passed value, return true if it matches, false otherwise.

R. Arctor
  • 718
  • 4
  • 15
0

You are currently using a for each loop to go through every value in the list to check if it has both the key and value that you are looking for. Part of the appeal of using a dictionary is that you don't have to iterate through it to find the key/value pair that you want, you can get the value of the entry you want through indexing it with WaywardSonDict["Genre"].

In your instance, the code could read:

if key in WaywardSonDict && WaywardSonDict[key] == value:
    return true;
return false;
Wonky
  • 11
  • 2
0

To expand on not_speshal's answer:

What lead to multiple boolean prints?

The issue's in your code are:

  • printing in the loop will print for each entry in dict
  • not returning, means looping through the complete dictionary

Solving iteratively

You can solve these issues, improve code and learn step by step (iteratively).

1. make it return

# rename from `valueDict` to a question in order to signal boolean return
def hasKeyWithValue(key,value):
    for i, j in WaywardSonDict.items():
        if i == key and j == value:
            return True
        # no else, simply continue looping to the end
    return False  # if not found and returned, finally return False


print(hasKeyWithValue('Genre', 'Hard Rock') # prints: True

Design advice: rename the function to signal expected boolean. This can be done by naming it like a question.

2. use dict's getter function instead of loop

def hasKeyWithValue(key,value):
    if WaywardSonDict.get(key) == value:
        return True
    else:
        return False

Then you need a complete if-else. Alternatively you could substitute the else by a default return:

def hasKeyWithValue(key,value):
    if WaywardSonDict.get(key) == value:
        return True  # that's the "unexpected"
    return False  # that's the default

Note: .get is special here, because it will return None if the key is not found. This allows for non-existence checks like hasKeyWithValue('Year',None) which will return True because the given dictionary has no entry with key Year.

3. simplify the if-return

def hasKeyWithValue(key,value):
    return (WaywardSonDict.get(key) == value)

Simplify the test. The if-else statement is obsolete, because the boolean expression (inside parentheses) evaluates to either True or False.

4. inline the simple test

key = 'Genre'
value = 'Hard Rock'

print(WaywardSonDict.get(key) == value)

So the hasKeyWithValue function has been replaced by a short ideomatic dictionary-test (that most Python developers can understand).

5. improve readability

# format like a table to ease reading
WaywardSonDict = {
    "Artist" : "Kansas",
    "Song"   : "Carry on Wayward Son",
    "Genre"  : "Hard Rock",
    "Album"  : "Leftoverture",
    "Writer" : "Kerry Livgren"
}

This way you can easily scan the dictionary entries like a check-list.

hc_dev
  • 8,389
  • 1
  • 26
  • 38