Jane
Jane

Reputation: 269

get dict value by part of the key python

I want to get value from the dictionary by the part of the key, e.g. I have a dict with a compound key

tr_dict = {'UTABI-OSGAN': {"properties": {"id": "789"}},
       'ABOKA-OSGAN': {"properties": {"id": "111"}},
       'FE-DERIG': {"properties": {"id": "243"}}}

and I want to get values with key started 'UTABI' (the other case when key endswith e.g. 'DERIG')

I suppose it looks something like

start = 'UTABI' 
tr_dict.get(start + '[-A-Z]{2,5}')

I know this syntax is incorrect but is it possible to do something like this?

Upvotes: 1

Views: 4616

Answers (3)

bruno desthuilliers
bruno desthuilliers

Reputation: 77912

Short answer: no. Dicts are not SQL databases, you have to give the exact key.

The brute force solution is to loop over the dict's keys and use string methods to find the relevant ones, ie:

for key in tr_dict:
    if key.startswith("UTABI-"):
        print("found {} : {}".format(key, tr_dict[key]))

which of course is O(n) and kind of defeat the whole point of having dicts. This is ok if you only need to do this lookup once for a given tr_dict, but sub-optimal if tr_dict has a long lifetime and will be looked up more than once for a given "partial" key.

Another solution which requires more upfront processing but allow for O(1) access afterward is to preprocess the whole dict once to build a new one with keys you can lookup directly:

from collections import defaultdict

lookups = [
   # (key: callback)
   ("UTABI", lambda k: k.startswith("UTABI-")),
   ("DERIG", lambda k: k.endswith("-DERIG")),
   ]

index = defaultdict(list)
for newkey, match in lookups:
    for oldkey in tr_dict:
        if match(oldkey):
            index[newkey].append(tr_dict[oldkey])

This is overkill for a one-shot lookup, but much better if you have to lookup those keys more than once for a given tr_dict.

Upvotes: 3

Vineeth Sai
Vineeth Sai

Reputation: 3445

Here's one way of doing it,

return_values = {k:v for k,v in tr_dict.items() if k.startswith('UTABI') or k.endswith('DERIG')}
print(return_values)

Outputs:

{'UTABI-OSGAN': {'properties': {'id': '789'}}, 'FE-DERIG': {'properties': {'id': '243'}}}

And here's the expanded form, that does the same thing

return_values = []
for k,v in tr_dict.items():
    if k.startswith('UTABI') or k.endswith('DERIG'): # Change your requirements here
        return_values.append(v)

print(return_values)

Upvotes: 0

artragis
artragis

Reputation: 3713

The syntax you propose is interpreted as "give me the "UTABI[-A-Z]{2,5}" key".

As you want to filter "by intention" you can say :

filtered_dict = {key: value for key, value in tr_dict if key.startswith('UTABI')}

Upvotes: 0

Related Questions