简体   繁体   中英

is there a way to access a value from a nested dict and update value in the same dict based on searching a list?

dict_1 = {'key1': {'Type': '51', 'dn_range': 203, 'soft_DN': nan}}
{'key2': {'Type': '51', 'dn_range': 204, 'soft_DN': nan}}

A_list = [2031111, 2031112, 2031113, 2042222, 2042223]

My goal is to search A_list to locate the first integer that starts with 203 and 204,(2031111 and 2042222) and update the respective soft_DN value.

Updated dict should look like this:

dict_1 = {'key1': {'Type': '51', 'dn_range': 203, 'soft_DN': 2031111}}
{'key2': {'Type': '51', 'dn_range': 204, 'soft_DN': 2042222}}

First your dict is not formatted correctly, I suppose it's supposed to look like this:

dict_1 = {'key1': {'Type': '51', 'dn_range': 203, 'soft_DN': None},
      'key2': {'Type': '51', 'dn_range': 204, 'soft_DN': None}}

The simple way of doing this would be converting the numbers to strings then comparing the first 3 chars to the dn_range

>>> int(str(2031111)[:3])
203

That said I don't know how large your dataset is and if it is pretty large you'd want to save time by reducing how many times you loop through the list as your iterating the dict. To do so I suggest using itertools.groupby to get a dict of keys being the first 3 digits of the integers and the values being the first integer that shows. That said make sure your integers are grouped together by fist 3 chars otherwise you'll need another way of doing this.

from itertools import groupby
ranges = {int(k): next(v) for k, v in groupby(A_list, key=lambda i: str(i)[:3])}

Result:

{203: 2031111, 204: 2042222}

Then just loop through the dict and replace the values

for k, d in dict_1.items():
    d['soft_DN'] = ranges.get(d['dn_range'])

Result:

{'key1': {'Type': '51', 'dn_range': 203, 'soft_DN': 2031111}, 'key2': {'Type': '51', 'dn_range': 204, 'soft_DN': 2042222}}

This code below will work as you wish:

dict_1 = {'key1': {'Type': '51', 'dn_range': 203, 'soft_DN': -1}} 
dict_2 = {'key2': {'Type': '51', 'dn_range': 204, 'soft_DN': -1}}

A_list = [2031111, 2031112, 2031113, 2042222, 2042223]

for i, x in enumerate(A_list):
    #Get rid of unnecessary part
    x = str(x)
    x = x[:3]
    x = int(x)

    if x == dict_1["key1"]["dn_range"] and dict_1["key1"]["soft_DN"] == -1:
        dict_1["key1"]["soft_DN"] = A_list[i]    
    
    if x == dict_2["key2"]["dn_range"] and dict_2["key2"]["soft_DN"] == -1:
        dict_2["key2"]["soft_DN"] = A_list[i]

print(dict_1, dict_2)
  • Firstly I have separated the two dictionaries into dict_1 and dict_2 .
  • Then with the first three lines in for loop I am getting rid of the unnecessary part of the number (since we only want to check the first three digits)
  • Then I am checking key 'dn_range' . If the number matches it - then rewrite -1 to the first good number.

Assuming that the "first integer in A_list..." means the first index (as opposed to the smallest, in case the list is not sorted), then you can loop through the dictionary and search the A_list for each entry in the dict:

for key, entry in dict_1.items():
    dn_range = entry["dn_range"]
    for dn in A_list:
        if dn_range * 10000 <= dn < dn_range + 1 * 10000:
            entry["soft_DN"] = dn
            break

If A_list is sorted, then you can do a binary search to find the target dn value instead of going through the list one by one. This will speed up your algorithm considerably.

I guess there's no magic here in Python. I would just:

  • Iterate over the entries of dict_1 and for each entry:
    • Get the dn_range field
    • Iterate over the items of A_list and for each item:
      • Check whether the item starts with dn_range (string representations can help here, strings have a startsWith() method) and, if so:
        • Update the dict entry and break out of the list iteration loop.

Python loops are much like pseudo code loops, easy to write and read. You will love them: Hints:

for key, value in dict_1.items():
for item in A_list:
if str(my_item).startsWith(str(d_range)):

Enough hints, happy coding!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM