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
source to share
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" }
source to share
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)
source to share
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')])
source to share