Python Dictionary: Compare keys with Values of All Keys

10,672

Solution 1

Try with:

test_dict = {'bat': [['gum', 'glove', 'knee']],
 'crowd': [['big', 'nice', 'large']],
 'glove': [['mitt', 'ball', 'bat']]}

def find_matches(dict1):
    match_dict = {}
    base_keys = dict1.keys()
    for key, values in dict1.items():
        for words in values:
            for base_key in base_keys:
                if base_key in words:
                    match_dict.update({key: base_key})
    return match_dict

print(find_matches(test_dict)) #{'bat': 'glove', 'glove': 'bat'}

Multiple for is because you have a [['mitt', 'ball', 'bat']] bidimensional list.

Maybe is more clear using set

EDIT

You post the antoher example dict without bidemensional values in dict, the sol is simple, delete a for like:

test_dict={'cubed': ['zryba', 'aszcb', 'btadc', 'melon', 'ewdgf'],
    'melon': ['jbilk', 'kcjml', 'cubed', 'nfmpo', 'ognqp'],
    'poop': ['mllm', 'nmmn', 'onno', 'qppq', 'rqqr']}

def find_matches(dict1):
    match_dict = {}
    base_keys = dict1.keys()
    for key, values in dict1.items():
        for base_key in base_keys:
            if base_key in values:
                match_dict.update({key: base_key})
    return match_dict

print(find_matches(test_dict)) #{'cubed': 'melon', 'melon': 'cubed'}

Solution 2

The following works for me:

test_dict={'cubed': ['melon', '2', '3', '4', '5'],
           'melon': ['2', 'poop', '4', '5', '6'],
           'poop': ['3', '4', '5', '6', 'cubed']}

d = defaultdict(str)
# iterate over keys and values
for key, values in test_dict.items():
    # iterate over values
    for val in values:
        # if val is a key
        if val in [x for x in test_dict.keys() if x != key]:
            # set dict[key] = val
            d[key] = val
print(d) 

defaultdict(<class 'str'>, {'melon': 'poop', 'poop': 'cubed', 'cubed': 'melon'})

Essentially, you check all the values against the list of keys, excluding the current key. If you want the returned dict to contain more than one value, use lists or sets:

defaultdict(list) or defaultdict(set)

and append the values

d[key].append(val) or d[key].add(val)

Solution 3

You can actually solve this problem with a dict comprehension. You just need to iterate over the names and lists in test_dict until you find a name which is both in the dict and a list:

>>> {n1:n2 for n1 in test_dict for n2 in test_dict[n1] if n2 in test_dict}
{'cubed': 'melon', 'melon': 'cubed'}

Solution 4

If your problem statement is correct, then your trouble lies in the fact that your test_dict is a dictionary mapping strings to lists of lists instead of mapping them to a list of words.

Your find_matches function iterates over the dictionary, placing the string key into key and the list-of-lists-of-words into value.

You then try to iterate over value. But of course if value is set to

[['gum', 'glove', 'knee']]

then when you do

    for word in value:

the variable word will take on the value ['gum', 'glove', 'knee'] and then the loop will end, because value only contains one element - a sublist of three words.

You can confirm this by printing key and then printing each word in your loop - I expect you will only see one line, with a list of words.

To fix this, ideally you would change the format of your dictionary. Why store a list of 1 list of words? Why not just store a list-of-words directly?

If that is impossible for some reason, then you will need to decide how to proceed: if there are more than one list-of-words, do you want to scan them all, or only the first such list?

# Scan the first list:
for word in value[0]:
    ...

# Scan all the lists:
for sublist in value:
    for word in sublist:
        ...
Share:
10,672

Related videos on Youtube

Z_D
Author by

Z_D

Updated on June 04, 2022

Comments

  • Z_D
    Z_D almost 2 years

    I am working through a problem that requires me to compare elements in a dictionary containing words as keys and lists of words as values. See example below.

    test_dict={'cubed': ['zryba', 'aszcb', 'btadc', 'melon', 'ewdgf'],
        'melon': ['jbilk', 'kcjml', 'cubed', 'nfmpo', 'ognqp'],
        'poop': ['mllm', 'nmmn', 'onno', 'qppq', 'rqqr']}
    

    I would like to return a new dictionary which contains keys that match the values of other keys in the dictionary. My code below is incorrect, I think because it is only considering each key-value pair independently and comparing items within those pairs only. Is there a way to iterate across keys to get the desired result? My desired result is shown below.

    def find_matches(dict1):
        match_dict={}
        for key, value in dict1.items():
            for word in value:
                if key == word:
                    #rotate_dict[key]=word
                    match_dict[key].append(word)
        return match_dict
    
    find_matches(SO_example) #returns {}, but should return {'cubed':'melon','melon':'cubed'}
    

    Thank you for your help.

    • Jon Clements
      Jon Clements over 6 years
      Umm... well {k:v for k, values in test_dict.items() for v in values[0] if v in test_dict} should do it - but do you really have a one-element list containing a list?
    • Z_D
      Z_D over 6 years
      No, my test example was wrong - apologies. Please see edit above.
    • Jon Clements
      Jon Clements over 6 years
      I'm now confused what you want... You're using .append but don't have a list, but your output example cites a normal dict... what would the output be for the above?
  • Z_D
    Z_D over 6 years
    I think my test example is incorrect. The output of my real result is now above.
  • Z_D
    Z_D over 6 years
    Thank you! Per my question I'm clearly a beginner, so didn't think of the nice update method you used. Appreciate your help and the edit after I fixed the example.