Home > OS >  How to filter both the keys and values of a dict in python?
How to filter both the keys and values of a dict in python?

Time:04-19

I want to achieve a customized dict that return the items according to an attribute mode as follows:

class MyDict(dict):
    def __init__(self):
        super(MyDict, self).__init__()
        self.mode = True

mydict = MyDict()
# fill data {0:0, 1:1, 2:2, 3:3, ..., 9:9}
for i in range(10):
    mydict[i] = i

mydict.mode acts as a filter. For example, when mydict.mode is True, mydict works like it only has the first half items, and when mydict.mode is False, it only contains the remaining data.

mydict.mode=True
print(mydict)         # {0:0, 1:1, 2:2, 3:3, 4:4}
print(mydict.keys())  # [0, 1, 2, 3, 4]

mydict.mode=False
print(mydict)         # {5:5, 6:6, 7:7, 8:8, 9:9}
print(mydict.keys())  # [5, 6, 7, 8, 9]

The above code is only a simple example, the support for more complex filters is also expected.

At first, I want to filter items within the functions of dict. The problem is that the class dict in python is implemented by C language rather than python, I don't know which and where is the most original iter function. So I have to rewrite all functions for my customized dict, like keys(), items(), values(), __contains__, __getitem__ ...

Is there any better idea to achieve my customized dict?

CodePudding user response:

I hope this helps you,

mydict = MyDict()

for i in range(11):
  mydict[i] = i

mid_index = int(len(mydict.keys()) / 2)

if mydict.mode == True:
  new_keys = list(mydict.keys())[:mid_index]
  new_values = list(mydict.values())[:mid_index]

  new_dict = dict(zip(new_keys, new_values))

  print(new_dict)

else:
  new_keys = list(mydict.keys())[mid_index:]
  new_values = list(mydict.values())[mid_index:]

  new_dict = dict(zip(new_keys, new_values))

  print(new_dict)

This code first identifies the dictionary's middle key's index and then returns the values according to that.

CodePudding user response:

There's not really a lot that you need to implement - just 3 higher level function (keys, values, items) and 3 dunder functions (setitem, getitem, contains). Add a few helper functions to keep the code concise then you end up with:

class MyDict:
    def __init__(self, mode=True):
        self._dict = dict()
        self._mode = mode
    @property
    def mode(self):
        return self._mode
    @mode.setter
    def mode(self, mode):
        self._mode = mode
    def __split(self, list_):
        mid = len(self._dict) // 2
        return list_[:mid] if self._mode else list_[mid:]
    def __sublistK(self):
        return self.__split(list(self._dict.keys()))
    def __sublistV(self):
        return self.__split(list(self._dict.values()))
    def __sublistI(self):
        return self.__split(list(self._dict.items()))
    def keys(self):
        for k in self.__sublistK():
            yield k
    def values(self):
        for v in self.__sublistV():
            yield v
    def items(self):
        for k, v in self.__sublistI():
            yield k, v
    def __setitem__(self, k, v):
        self._dict[k] = v
    def __getitem__(self, k):
        if k in self:
            return self._dict[k]
    def __contains__(self, k):
        return k in self.__sublistK()

Now you can use this as a regular dictionary except that the output will be influenced by the mode value

  • Related