Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to raise error if duplicates keys in dictionary

I try to raise an error if the user enter a duplicate key in a dictionary. The dictionary is in a file and the user can edit the file manually.

Example:

dico= {'root':{
                'a':{'some_key':'value',...},
                'b':{'some_key':'value',...},
                'c':{'some_key':'value',...},
                ...

                'a':{'some_key':'value',...},
              }
      }

the new key 'a' already exist...

How can I test dico and warn the user when I load dico from the file?

like image 843
Thammas Avatar asked Feb 15 '11 01:02

Thammas


People also ask

How do dictionary handle duplicate keys?

If you want to keep duplicate keys in a dictionary, you have two or more different values that you want to associate with same key in dictionary. The dictionary can not have the same keys, but we can achieve a similar effect by keeping multiple values for a key in the dictionary.

Can you have a dictionary with duplicate keys?

Dictionaries do not support duplicate keys. However, more than one value can correspond to a single key using a list.

What happens when duplicate keys encountered during assignment in dictionary?

When duplicate keys are encountered during the assignment, the value will be the last assigned one. Keys must be immutable. This means you can use strings, numbers, or tuples as dictionary keys, but something like ['key'] is not allowed.


2 Answers

Write a subclass of dict, override __setitem__ such that it throws an error when replacing an existing key; rewrite the file to use your new subclass's constructor instead of the default dict built-ins.

import collections

class Dict(dict):
    def __init__(self, inp=None):
        if isinstance(inp,dict):
            super(Dict,self).__init__(inp)
        else:
            super(Dict,self).__init__()
            if isinstance(inp, (collections.Mapping, collections.Iterable)): 
                si = self.__setitem__
                for k,v in inp:
                    si(k,v)

    def __setitem__(self, k, v):
        try:
            self.__getitem__(k)
            raise ValueError("duplicate key '{0}' found".format(k))
        except KeyError:
            super(Dict,self).__setitem__(k,v)

then your file will have to be written as

dico = Dict(
    ('root', Dict(
        ('a', Dict(
            ('some_key', 'value'),
            ('another_key', 'another_value')
        ),
        ('b', Dict(
            ('some_key', 'value')
        ),
        ('c', Dict(
            ('some_key', 'value'),
            ('another_key', 'another_value')
        ),

        ....
    )
)

using tuples instead of dicts for the file import (written using the {} notation, it would use the default dict constructor, and the duplicates would disappear before the Dict constructor ever gets them!).

like image 177
Hugh Bothwell Avatar answered Oct 15 '22 14:10

Hugh Bothwell


If you want to ensure that an error is raised during dict construction with duplicate keys, just leverage Python's native keyword argument checking:

> dict(a={}, a={})
SyntaxError: keyword argument repeated

Unless I'm missing something, there is no need to subclass dict.

like image 24
Jian Avatar answered Oct 15 '22 13:10

Jian