简体   繁体   中英

Increment key if key already in dict

Im trying to auto increment a dict keys if a key already exists

I have achieve it using a while loop but I wonder if there would be a cleaner/faster way to do it

foo = {}
foo["a"] = "bar"
foo["a (1)"] = "baz"
key = "a"
count = 0
key_check = key
while key_check in foo:
    count += 1
    key_check = key + " ({})".format(count)

foo[key_check] = "bazzz"
print foo
>>>{'a': 'bar', 'a (1)': 'baz', 'a (2)': 'bazzz'}

I think what commenters are trying to explain is that you never need to change the name of the key when trying to do an operation like this one. Instead, you can build your logic so that the value in each key/value pair updates. For example, in this snippet, I have a list of words, and I want to know how many of each word I have. The part of the code after 'except' is the part that fires when the key isn't found. This example doesn't match your use case exactly, but I think/hope it demonstrates the overall point effectively.

tokens = ['now', 'when', 'i', 'say', 'that', 'i', 'am', 'in', 'the', 'habit', 'of', 'going', 'to', 'sea', 'whenever', 'i', 'begin', 'to', 'grow', 'hazy', 'about', 'the', 'eyes', 'and', 'begin', 'to', 'be', 'over', 'conscious', 'of', 'my', 'lungs', 'i', 'do', 'not', 'mean', 'to', 'have', 'it', 'inferred', 'that', 'i', 'ever', 'go', 'to', 'sea', 'as', 'a', 'passenger', 'for', 'to', 'go', 'as', 'a', 'passenger', 'you', 'must', 'needs', 'have', 'a', 'purse', 'and', 'a', 'purse', 'is', 'but', 'a', 'rag', 'unless', 'you', 'have', 'something', 'in', 'it', 'besides', 'passengers', 'get', 'sea', 'sick', 'grow', 'quarrelsome', 'dont', 'sleep', 'of', 'nights', 'do', 'not', 'enjoy', 'themselves', 'much', 'as', 'a', 'general', 'thing;', 'no', 'i', 'never', 'go', 'as', 'a', 'passenger;', 'nor', 'though', 'i', 'am', 'something', 'of', 'a', 'salt', 'do', 'i', 'ever', 'go', 'to', 'sea', 'as', 'a', 'commodore', 'or', 'a', 'captain', 'or', 'a', 'cook', 'i', 'abandon', 'the', 'glory', 'and', 'distinction', 'of', 'such', 'offices', 'to', 'those', 'who', 'like', 'them', 'for', 'my', 'part', 'i', 'abominate', 'all', 'honorable', 'respectable', 'toils', 'trials', 'and', 'tribulations', 'of', 'every', 'kind', 'whatsoever', 'it', 'is', 'quite', 'as', 'much', 'as', 'i', 'can', 'do', 'to', 'take', 'care', 'of', 'myself', 'without', 'taking', 'care', 'of', 'ships', 'barques', 'brigs', 'schooners', 'and', 'what', 'not', 'and', 'as', 'for', 'going', 'as', 'cook', 'though', 'i', 'confess', 'there', 'is', 'considerable', 'glory', 'in', 'that', 'a', 'cook', 'being', 'a', 'sort', 'of', 'officer', 'on', 'ship', 'board', 'yet', 'somehow', 'i', 'never', 'fancied', 'broiling', 'fowls;', 'though', 'once', 'broiled', 'judiciously', 'buttered', 'and', 'judgmatically', 'salted', 'and', 'peppered', 'there', 'is', 'no', 'one', 'who', 'will', 'speak', 'more', 'respectfully', 'not', 'to', 'say', 'reverentially', 'of', 'a', 'broiled', 'fowl', 'than', 'i', 'will', 'it', 'is', 'out', 'of', 'the', 'idolatrous', 'dotings', 'of', 'the', 'old', 'egyptians', 'upon', 'broiled', 'ibis', 'and', 'roasted', 'river', 'horse', 'that', 'you', 'see', 'the', 'mummies', 'of', 'those', 'creatures', 'in', 'their', 'huge', 'bake', 'houses', 'the', 'pyramids', 'no', 'when', 'i', 'go', 'to', 'sea', 'i', 'go', 'as', 'a', 'simple', 'sailor', 'right', 'before', 'the', 'mast', 'plumb', 'down', 'into', 'the', 'forecastle', 'aloft', 'there', 'to', 'the', 'royal', 'mast', 'head', 'true', 'they', 'rather', 'order', 'me', 'about', 'some', 'and', 'make', 'me', 'jump', 'from', 'spar', 'to', 'spar', 'like', 'a', 'grasshopper', 'in', 'a', 'may', 'meadow', 'and', 'at', 'first', 'this', 'sort', 'of', 'thing', 'is', 'unpleasant', 'enough', 'it', 'touches', 'ones', 'sense', 'of', 'honor', 'particularly', 'if', 'you', 'come', 'of', 'an', 'old', 'established', 'family', 'in', 'the', 'land', 'the', 'van', 'rensselaers', 'or', 'randolphs', 'or', 'hardicanutes', 'and', 'more', 'than', 'all', 'if', 'just', 'previous', 'to', 'putting', 'your', 'hand', 'into', 'the', 'tar', 'pot', 'you', 'have', 'been', 'lording', 'it', 'as', 'a', 'country', 'schoolmaster', 'making', 'the', 'tallest', 'boys', 'stand', 'in', 'awe', 'of', 'you', 'the', 'transition', 'is', 'a', 'keen', 'one', 'i', 'assure', 'you', 'from', 'a', 'schoolmaster', 'to', 'a', 'sailor', 'and', 'requires', 'a', 'strong', 'decoction', 'of', 'seneca', 'and', 'the', 'stoics', 'to', 'enable', 'you', 'to', 'grin', 'and', 'bear', 'it', 'but', 'even', 'this', 'wears', 'off', 'in', 'time']

result ={}
for i in tokens:
    try:
        result[i] +=1
    except:
        result[i] = 1

# result is {'now': 1,
# 'when': 2,
# 'i': 17,
# 'say': 2,
# 'that': 4,
# 'am': 2,
# 'in': 8,
# 'the': 16, ... }

A cleaner way is to use a mapping between key and a list of values for it. Use defaultdict for this. If a key isn't present, it will call the defaultfactory function* and returns it.
* here a default factory function is the list function that returns an empty list

from collections import defaultdict

# foo=[("a", "bar"), ("a", "bazz")] # some random input that maps keys to values, and keys repeat
foobarbaz = defaultdict(list) # return empty list if key doesn't exist
for k, val in foo:
    foobarbaz[k].append(val)
# If you don't want a simple dict instead of defaultdict
foobarbaz = dict(foobarbaz)
print(foobarbaz)
>>>{'a': ['bar', 'bazzz']}

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