How to dynamically extract data from multiple Python dict entries

Viewed 199

Let's say I have a dict like this:

my_dict = {something: 'blabla', result: 'something', value_0_0: 'apple', value_0_1: 'ball', value_1_0: 'banana', value_1_1: 'car', value_2_0: 'orange', value_2_1: 'toy'}

The dict may have other key-value entries with other names like: result: 'something'. I just want to filter those keys with the following structure:

value_X_Y

Desired output:

0values = "apple ; banana ; orange"

1values = "ball ; car; toy"

If the size of the dictionary was fixed, you could do something like this:

for x in my_dict:
    if(x == 'value_0_0'):
        #do something
    if(x == 'value_0_1'):
        #do something
    if(x == 'value_1_0'):
        #do something
    if(x == 'value_1_1'):
        #do something
    if(x == 'value_2_0'):
        #do something
    if(x == 'value_2_1'):
        #do something

But since the dictionary do not have a fixed size and can have 3 values or 50 (for example) value_50_0, value_50_1, I would like to process the data dynamically.

How could I get something like that?

Any insights will be appreciated.

5 Answers

The following example uses a regex to identify the keys starting with "value_" and captures the last number to use it to create a new dictionary with an array and the related values:

import re

my_dict = {'something': 'blabla', 'result': 'something','value_0_0': 'apple', 'value_0_1': 'ball', 'value_1_0': 'banana', 'value_1_1': 'car', 'value_2_0': 'orange', 'value_2_1': 'toy'}
result = {}

for key, value in my_dict.items():
    # Get last number from the key to be used as the key of the result array
    m = re.match(r'^value\_\d+\_(\d+$)', key)
    if m is not None:
        result_key = m.groups()[0] + 'values'
        if not result_key in result:
            result[result_key] = []
        
        result[result_key].append(value)

print(result)

Result:

{'0values': ['apple', 'banana', 'orange'], '1values': ['ball', 'car', 'toy']}
my_dict = {'value_0_0': 'apple', 'value_0_1': 'ball', 'value_1_0': 'banana', 'value_1_1': 'car','value_2_0': 'orange', 'value_2_1': 'toy'}
fruits,acces=[],[]
for key,value in my_dict.items():
    if 0 == int(key.split('_')[-1]):
        fruits.append(value)
    if 1 == int(key.split('_')[-1]):
        acces.append(value)

fruits and acces will be a list with respective data

fruits = ['apple', 'banana', 'orange']
acces = ['ball', 'car', 'toy']

If you're just looking to iterate through the dictionary, you can use the dict.keys(), dict.values(), or dict.items() methods. You could then create a new dictionary mapping the various values ("0values", "1values", etc.) to the appropriate string values.

Something like this, perhaps:

import re

values = {}

# Create a regular expression to match strings in the format 'value_X_Y'
regex = re.compile(r"^value_\d+_(\d+)$")

for key, val in my_dict.items():
    # Try to match 'Y' in 'value_X_Y', or else skip the key-value pair
    keynum = regex.search(key)
    if keynum is None:
        continue

    # Update dictionary with formatted key and value 
    value_key = f"{keynum.group(1)}values"
    values.setdefault(value_key, [])
    values[value_key].append(val)

Here, the dict.setdefault() method will create the key value_key and set it to [], provided that value_key does not already exist in the dictionary. This would be the same as checking for the key in the dictionary 'manually':

if value_key not in values:
    values[value_key] = []

With the dictionary provided, some sample usage:

>>> import re
>>> my_dict = {
    "value_0_0": "apple",
    "value_0_1": "ball",
    "value_1_0": "banana",
    "value_1_1": "car",
    "value_2_0": "orange",
    "value_2_1": "toy"
}
>>> values = {}
>>> regex = re.compile(r"^value_\d+_(\d+)$")
>>> for key, val in my_dict.items():
        keynum = regex.search(key)
        if keynum is None:
            continue
        value_key = f"{keynum.group(1)}values"
        values.setdefault(value_key, [])
        values[value_key].append(val)

>>> values
{'0values': ['apple', 'banana', 'orange'], '1values': ['ball', 'car', 'toy']}

Then with some formatting, it's not too hard to get the desired output:

>>> for key, val in values.items():
        print(f"{key}: {'; '.join(val)}")

    
0values: apple; banana; orange
1values: ball; car; toy

You can use the split method here on keys of the dictionary to extract the numbers and then process the information.

my_dict = {"value_0_0": 'apple', "value_0_1": 'ball', "value_1_0": 'banana', "value_1_1": 'car', "value_2_0": 'orange', "value_2_1": 'toy'}

results = {}

for key, value in my_dict.items():
    _, _, y = key.split("_")

    if y not in results:
        results[y] = []

    results[y].append(value)

for k, v in results.items():
    print(k+"values", "=", "; ".join(v))

With using re for matching keys and defaultdict to avoid checking if an element exists in the dict and some short circuiting with and you can do somthing like this:

import re
from collections import defaultdict

res = defaultdict(list)

for key, val in my_dict.items(): 
    (r := re.findall('value_\d+_(\d+)', key)) and res[f'{r[0]}values'].append(val)

res = dict(res)

You can leave out the last line if you're okay with the defaultdict as an outcome.

Related