Search pythondict dictionary key by regular expression

I want to search the dict key with a regular expression

The dict dictionary is fast and very easy to use. If you want to search for a key with a regular expression, you would normally do this, but if you use it a lot, it's a hassle.

a = dict(abc=1, def=2) #-> {"abc": 1, "def": 2}
s = re.compile(".bc")
ret = []
for k in a:
    if s.search(k):
        ret.append(a[k])
print(ret) #-> [1]

#It looks like this at best even if it is shortened by the inclusion notation, but it is not readable and I do not know what I wanted to do when I read the source when I forgot.
s = re.compile(".bc")
[a[k] for k in a if s.search(k)] #-> [1]

Since this is troublesome, I extended the standard dict so that it can be used like this.

a = rdict(abc=1, def=2) #-> {"abc": 1, "def": 2}
a.search(".bc") #-> [1]

The source is like this.

import re
from functools import lru_cache

@lru_cache(16) # re.Since compile is a fairly heavy process, the same regular expression pattern is cached to gain performance.
def re_call(pattern, flags=0, call_re_func="search"):
    return re.compile(pattern, flags=flags).__getattribute__(call_re_func)

class rdict(dict):
    def _filter(self, _callable):
        return (k for k in self if _callable(k))

    def isin(self, key_or_function):
        if callable(key_or_function):
            return any(True for _ in self._filter(key_or_function))
        return dict.__contains__(self, key_or_function)

    def findall(self, key_or_function):
        if callable(key_or_function):
            return [dict.__getitem__(self, key) for key in self._filter(key_or_function)]
        return dict.__getitem__(self, key_or_function)

    def search(self, pattern, flags=0):
        return [dict.__getitem__(self,key) for key in self if re_call(pattern, flags, "search")(key)]

    def fullmatch(self, pattern, flags=0):
        return [dict.__getitem__(self,key) for key in self if re_call(pattern, flags, "fullmatch")(key)]

    def __setitem__(self, key_or_function, value):
        if callable(key_or_function):
            for key in self._filter(key_or_function):
                dict.__setitem__(self, key, value)
        else:
            return dict.__setitem__(self, key_or_function, value)

    def __delitem__(self, key_or_function):
        if callable(key_or_function):
            for key in list(self._filter(key_or_function)):
                dict.__delitem__(self, key)
        else:
            return dict.__delitem__(self, key_or_function)

I've added some other functions, but here's an image of how to use them.

Find out if there is a matching key in the regular expression pattern


    >>> a.isin(re.compile(".b.*").search)
    True
    >>> a.isin(re.compile(".z.*").search)
    False

Other 1. Returns the value when having a key when the condition is true.

    >>> a.findall(lambda x: len(x) == 3)
    [1, 2]

Other 2. Search the key in the range and return the value If the argument of findall is callable, anything works, so the following applications are also possible


    >>> from datetime import datetime
    >>> b = funcdict()
    >>> b[datetime(2020,1,1)] = "2020/01/01"
    >>> b[datetime(2020,2,1)] = "2020/02/01"
    >>> b[datetime(2020,3,1)] = "2020/03/01"

    >>> def between_0131_0202(x):
    ...    return datetime(2020,1,31) < x and x < datetime(2020,2,2)
    >>> b.findall(between_0131_0202)
    ['2020/02/01']

    >>> def less_0401(x):
    ...    return x < datetime(2020, 4, 1)
    >>> b.isin(less_0401)
    True

    >>> def grater_0401(x):
    ...    return x > datetime(2020, 4, 1)
    >>> b.isin(grater_0401)
    False

    >>> b.findall(less_0401)
    ['2020/01/01', '2020/02/01', '2020/03/01']

After that, the function to change the value of the key that matches the condition at once

    >>> b[less_0401] = "test"
    >>> b
    {datetime.datetime(2020, 1, 1, 0, 0): 'test',
     datetime.datetime(2020, 2, 1, 0, 0): 'test',
     datetime.datetime(2020, 3, 1, 0, 0): 'test'}

By the way, the function to delete all the keys that match the conditions at once

    >>> del b[between_0131_0202]
    >>> b
    {datetime.datetime(2020, 1, 1, 0, 0): 'test',
     datetime.datetime(2020, 3, 1, 0, 0): 'test'}

Recommended Posts

Search pythondict dictionary key by regular expression
Regular expression Greedy
Regular expression re
Data batch extraction method by regular expression from Series
Regular expression in regex.h
Regular expression look-ahead, after-yomi
python regular expression memo
Regular expression matching method
Regular expression in Python
Regular expression in Python
Regular expression confirmation quiz!
Value sort of dictionary with complicated structure (sort by key structure by deep value)