Rickson
Rickson

Reputation: 1090

Most pythonic way to append Dictionary with specific keys

A dictionary like Dict = {'Key_1': 'Data_1', 'Key_2': 'Data_2', ..., 'Key_n': 'Data_n'} contains n keys named in ascending order.

A method like AddNextKey(Dict, NewData) should determine the last key n and add a new one n+1 with value NewData. If Dict is empty, the method should append key Key_1.

I am quite sure that a pythonic solution does not require more than two or three lines of code to achieve this.

Remark: It is not important that the dictionary is ordered. Only the correct next key (n+1) must be appended.

Could anybody give advice?

Upvotes: 0

Views: 444

Answers (7)

vasi1y
vasi1y

Reputation: 815

There is no order in a dictionary. And you can not get the last inserted element from it.

Take a look at this example:

>>> {'Key_1': 'Data_1', 'Key_2': 'Data_2'} == {'Key_2': 'Data_2', 'Key_1': 'Data_1'}
True

As you can see, the order is meaningless for the dict.

The question is what exactly do you mean by the last key n. Last inserted? Or with biggest key_%index%? In first case you better to use OrderedDict, as already mentioned.

However, here is my solution, if I got you right.

def AddNextKey(Dict, NewData):
    Dict['Key_%d' % (len(Dict) + 1)] = NewData

d = {}
AddNextKey(d, 'Data_1')
AddNextKey(d, 'Data_2')
AddNextKey(d, 'Data_3')

print d

You will get

{'Key_1': 'Data_1', 'Key_3': 'Data_3', 'Key_2': 'Data_2'}

Upvotes: 1

Vaishali
Vaishali

Reputation: 38415

By definition, python dictionary are an unordered set of key: value pairs, with the requirement that the keys are unique. Given that you can use OrderedDict from class collections to create and update the dictionary and preserve the order.

from collections import OrderedDict
d1 = OrderedDict([(1, 'Data_1'), (2, 'Data_2'),(3, 'Data_3')])

You get

OrderedDict([(1, 'Data_1'), (2, 'Data_2'), (3, 'Data_3')])

Now the method to update the dictionary

def AddNextKey(Dict, NewData):
    last_key = next(reversed(Dict))
    new_key = last_key + 1
    Dict.update({new_key: NewData})

When you call

AddNextKey(d1, 'Blah')

You get

OrderedDict([(1, 'Data_1'), (2, 'Data_2'), (3, 'Data_3'), (4, 'Blah')])

Upvotes: 0

yogabonito
yogabonito

Reputation: 657

Something you need is already built into Python. So I think the most pythonic way is to use OrderedDict. As the docs say

Return an instance of a dict subclass, supporting the usual dict methods. An OrderedDict is a dict that remembers the order that keys were first inserted. If a new entry overwrites an existing entry, the original insertion position is left unchanged. Deleting an entry and reinserting it will move it to the end.

from collections import OrderedDict
d = OrderedDict()
d["Key1"] = 1
d["Key2"] = 2
d["Key3"] = 3

last_key = d.keys()[-1]  # "Key3" thanks to ordering
new_key = calculate_new_key(last_key)
d[new_key] = new_value

Upvotes: 0

Roland Smith
Roland Smith

Reputation: 43533

Normal Python dictionaries are unordered. So technically, there is no "last" key.

But there is a way around that. You could use the len method to see how many items there are in the dictionary, and construct the next key based on that.

But note that this method is fragile. if you accidentally add a key 'foo' to the dictionary, your whole scheme is off.

To really fix this you would have to create a subclass of dict (by overriding the __setitem__ and update methods as shown in this answer) so that it only accepts valid keys in the form 'Key_N'. You could then also add an append method to automatically create the next key.

But as turbulencetoo commented, it would probably be easier to use a list.

Upvotes: 1

Kyrubas
Kyrubas

Reputation: 897

# set-up the dictionary for demo purposes
testdict = {x:y for x,y in zip(["Key_"+str(x) for x in range(1,7)],
                               ["Data_"+str(x) for x in range(1,7)])}

# fetch most recent key
# add 1 to recent_key_val and insert new value
if len(testdict) != 0:
    recent_key_val = max([int(x.split("_")[1]) for x in testdict])
    testdict["Key_"+str(recent_key_val +1)] = "New_Data"
else:
    testdict["Key_1"] = "New_Data"

Upvotes: 0

Tagc
Tagc

Reputation: 9072

I'm not sure if it's the most Pythonic solution but my approach is to subclass dict and add that additional method. Since it's a subclass, you can use an instance of NextKeyDict anywhere you could an actual dict, but also perform these special operations where needed.

class NextKeyDict(dict):
    def add_next_key(self, new_data):
        if not self.keys():
            self[0] = new_data
            return

        last_key = sorted(self.keys())[-1]
        new_key = last_key + 1
        self[new_key] = new_data

d = NextKeyDict()
d.add_next_key('foo')
d.add_next_key('bar')
d.add_next_key('baz')
print(d)

Output

{0: 'foo', 1: 'bar', 2: 'baz'}

Upvotes: 2

Michael Ellner
Michael Ellner

Reputation: 116

You could use the length of the dictionary

Dict = dict()
for i in range(10):
    Dict['key_' + str(len(Dict)+1)] = 'value_'+str(len(Dict)+1)
print Dict

Outputs

{'key_10': 'value_10', 'key_5': 'value_5', 'key_4': 'value_4', 'key_7': 'value_7', 'key_6': 'value_6', 'key_1': 'value_1', 'key_3': 'value_3', 'key_2': 'value_2', 'key_9': 'value_9', 'key_8': 'value_8'}

Upvotes: 1

Related Questions