Increasing python dictionary value based on counter

I have a dictionary with duplicate values.

Deca_dict = {
    "1": "2_506",
    "2": "2_506",
    "3": "2_506",
    "4": "2_600",
    "5": "2_600",
    "6": "1_650"
}

      

I have used collections. Casting to count how many there are.

decaAdd_occurrences = {'2_506':3, '2_600':2, '1_650':1}

      

Then I created a new dictionary of values ​​to update.

deca_double_dict = {key: value for key, value in Deca_dict.items()
                        if decaAdd_occurrences[value] > 1}
deca_double_dict = {
    "1": "2_506",
    "3": "2_506",
    "2": "2_506",
    "4": "2_600"
}

      

(in this case it is the original dict without the last element)

I am trying to figure out how to increment a number, for counter_dict values ​​minus 1. This will update all values ​​except one, which may remain the same. Target output allows one of the duplicates to keep the same value, while the rest will have the first row number of values ​​increasing more frequently (depending on the number of duplicated counts). I am trying to achieve unique values ​​for the data presented by the original Deca_dict.

Goal output = {'1':'3_506', '2':'4_506', '3':'2_506', '4':'3_600', '5':'2_600'}

      

I started to iterate over things like this, but ended up just incrementing all the doubles, leaving me initially except for the plus one values. For context: the original Deca_dict values ​​were found by concatenating two numbers (deca_address_num and deca_num_route). In addition, homesLayer is a QGIS feature layer where deca_address_num and deca_num_route are stored in d_address_idx and id_route_idx fields.

for key in deca_double_dict.keys():
    for home in homesLayer.getFeatures():
        if home.id() == key:
            deca_address_num = home.attributes()[d_address_idx]
            deca_num_route = home.attributes()[id_route_idx]
            deca_address_plus = deca_address_num + increment
            next_deca_address = (str(deca_address_plus) + '_' +
                                 str(deca_num_route))
            if not next_deca_address in Deca_dict.values():
                update_deca_dbl_dict[key] = next_deca_address

      

The result is useless:

Update_deca_dbl_dict = {
    "1": "3_506",
    "3": "3_506",
    "2": "3_506",
    "5": "3_600",
    "4": "3_600"
}

      

My second attempt is trying to turn on the counter, but everything is in the wrong place.

for key, value in deca_double_dict.iteritems():
    iterations = decaAdd_occurrences[value] - 1
    for home in homesLayer.getFeatures():
        if home.id() == key:
            #deca_homeID_list.append(home.id())
            increment = 1
            deca_address_num = home.attributes()[d_address_idx]
            deca_num_route = home.attributes()[id_route_idx]
            deca_address_plus = deca_address_num + increment
            next_deca_address = (str(deca_address_plus) + '_' +
                                 str(deca_num_route))
            #print deca_num_route
            while iterations > 0:
                if not next_deca_address in Deca_dict.values():
                    update_deca_dbl_dict[key] = next_deca_address
                    iterations -= 1
                    increment += 1

      

UPDATE Even though one of the answers below works for increasing all duplicate items in my dictionary, I am trying to redo my code as I need this comparison condition to be the original data to grow. I still have the same result as my first attempt (useless).

for key, value in deca_double_dict.iteritems():
    for home in homesLayer.getFeatures():
        if home.id() == key:
            iterations = decaAdd_occurrences[value] - 1
            increment = 1
            while iterations > 0:
                deca_address_num = home.attributes()[d_address_idx]
                deca_num_route = home.attributes()[id_route_idx]
                deca_address_plus = deca_address_num + increment
                current_address = str(deca_address_num) + '_' + str(deca_num_route)
                next_deca_address = (str(deca_address_plus) + '_' +
                                 str(deca_num_route))
                if not next_deca_address in Deca_dict.values():
                    update_deca_dbl_dict[key] = next_deca_address
                    iterations -= 1
                    increment += 1
                else:
                    alpha_deca_dbl_dict[key] = current_address
                    iterations = 0

      

+3


source to share


3 answers


I think this does what you want. I've modified your input dictionary a bit to better illustrate what's going on. The main difference from what you were doing is that the decaAdd_occurrences

created from the dictionary Counter

keeps track of not only the number, but also the value of the current address num

. This lets you know to use the next value num

, since both it and the score are updated during the change Deca_dict

.

from collections import Counter

Deca_dict = {
    "1": "2_506",
    "2": "2_506",
    "3": "2_506",
    "4": "2_600",
    "5": "1_650",
    "6": "2_600"
}

decaAdd_occurrences = {k: (int(k.split('_')[0]), v) for k,v in
                                Counter(Deca_dict.values()).items()}

for key, value in Deca_dict.items():
    num, cnt = decaAdd_occurrences[value]
    if cnt > 1:
        route = value.split('_')[1]
        next_num = num + 1
        Deca_dict[key] = '{}_{}'.format(next_num, route)
        decaAdd_occurrences[value] = next_num, cnt-1  # update values

      



Updated dictionary:

Deca_dict -> {
    "1": "3_506",
    "2": "2_506",
    "3": "4_506",
    "4": "3_600",
    "5": "1_650",
    "6": "2_600"
}

      

+1


source


Is this roughly what you want? I assume you can deal with a function to change 2_506 to 3_506 etc. Instead of your counter, I use a set to ensure there are no duplicate values.

In the original post, I cut the line at the bottom, sorry.



values_so_far = set()
d1 = {} # ---your original dictionary with duplicate values---
d2 = {} # d1 with all the duplicates changed
def increment_value(old_value):
    # you know how to write this
    # return the modified string

for k,v in d1.items():
    while v in values_so_far:
        v = increment_value(v)
    d2[k] = v
    values_so_far.add(v)

      

+1


source


Here's the solution: Essentially it keeps the first of the duplicate values ​​and increments the extension of the remaining duplicates left.

from collections import OrderedDict, defaultdict
orig_d = {'1':'2_506', '2':'2_506', '3':'2_506', '4':'2_600', '5':'2_600'}
orig_d = OrderedDict(sorted(orig_d.items(), key=lambda x: x[0]))

counter = defaultdict(int)
for k, v in orig_d.items():
    counter[v] += 1
    if counter[v] > 1:
        pre, post = v.split('_')
        pre = int(pre) + (counter[v] - 1)
        orig_d[k] = "%s_%s" % (pre, post)

print(orig_d)

      

Result:

OrderedDict([('1', '2_506'), ('2', '3_506'), ('3', '4_506'), ('4', '2_600'), ('5', '3_600')])

      

+1


source







All Articles