Search code examples
pythondictionaryinverse

How to check if a dictionary is invertible


I am working on a question that requires to point out the problem in a function that determines whether a dictionary is invertible (for every value appearing in the dictionary, there is only one key that maps to that value) or not. The question is below:

def is_invertible(adict):
    inv_dict = make_inv_dict(adict)
    return adict == inv_dict

def make_inv_dict(adict):
    if len(adict) > 0:
       key, val = adict.popitem()
       adict = make_inv_dict(adict)
       if val not in adict.values():
          adict[key] = val
       return adict
    else:
        return {}

Currently, this returns False for {'a': 'b', 'b': 'e', 'c': 'f'} when it is supposed to be True. I am sure that there is an issue in make_inv_dict function; is it simply because adict is not an appropriate variable name in adict = make_inv_dict(adict)? Or is there another reason why the function returns a wrong outcome?


Solution

  • At least three problems with the function you've given:

    1. The condition adict == inv_dict checks whether the dictionary is its own inverse, not merely that it's invertible.
    2. It uses pop_item to remove a key/value pair from the input dictionary, and then inserts it backwards, so the function operates in-place. By the time it's finished, adict's original contents will be completely destroyed, so the comparison will be meaningless anyway.
    3. The line adict[key] = val inserts the key/value pair in the original order; the inverse order should be adict[val] = key. So this function doesn't do what its name promises, which is to make an inverse dictionary.

    It should be noted that if not for the destruction of the dictionary (2.), the mistakes (1.) and (3.) would cancel out, because the outcome of the function is to rebuild the original dictionary but without duplicate values.


    I'm guessing some people will find this question if they're looking for a correct way to invert a dictionary, so here is one: this function returns the inverse dictionary if it's possible, or None otherwise.

    def invert_dict(d):
        out = dict()
        for k,v in dict.items():
            if v in out:
                return None
            out[v] = k
        return out
    

    Helper function returning a boolean for whether a dictionary is invertible:

    def is_invertible(d):
        return invert_dict(d) is not None