Jim
Jim

Reputation: 875

Shifting dictionary elements

I have a dictionary of an undefined size (as big as the user wants) but I want to be able to delete items in the dictionary if needed, my question is how to I move all of the dictionary keys once one has been removed, i.e

transDict={0:"Charlie", 1:"Alan", 2:"Jake", 3:"Rose"}
delkey = raw_input('What key to delete')
transDict[delkey] = transDict.pop[int(delkey + 1)]

# this is the bit isn't working code just an 
# example of the functionality I need
for _id in transDict.keys(int(delkey) + 1:):
    transDict[_id] = transDict[(int(_id) + 1)]

but then I need to shift all other elements from 3 onwards down a step, the problem I have is the dictionary can be 5 or 50 elements big.

Thanks

Upvotes: 4

Views: 8964

Answers (4)

zmo
zmo

Reputation: 24812

You should definitely be using a list for such a feature, which would handle that feature per design.

>>> for i in l:
...     print(l.index(i), i)
... 
(0, 'Charlie')
(1, 'Alan')
(2, 'Jake')
(3, 'Rose')
>>> del l[2]
>>> for i in l:
...     print(l.index(i), i)
... 
(0, 'Charlie')
(1, 'Alan')
(2, 'Rose')

But for the sake of answering your question here's a solution:

>>> def remove_key(d, del_key):
...     new_dict = {}
...     for key, val in d.items():
...         if key < del_key:
...             new_dict[key] = val
...         elif key > del_key:
...             new_dict[key-1] = val
...         else: # key == del_key
...             continue
...     return new_dict
... 
>>> transDict={0:"Charlie", 1:"Alan", 2:"Jake", 3:"Rose"}
>>> remove_key(transDict, 2)
{0: 'Charlie', 1: 'Alan', 2: 'Rose'}

What was wrong in your algorithm:

for _id in transDict.keys(int(delkey) + 1:):
    transDict[_id] = transDict[(int(_id) + 1)]

it is that,

  • you're using range syntax within argument of the keys() method. The right syntax is to use the [] operator, e.g. .keys()[2:],
  • you're iterating through all the indexes starting at position delkey+1 of your dictionary, discarding the two possibilities, and you're shifting all the following values by one:
    • the keys are unlikely to be ordered (because of the dict's definition),
    • the keys might be sparse, which is likely to happen after a few keys removal.

So to build the algorithm I suggested you, I'm building a new dictionary, and while copying keys from the first dictionary to the new one, I consider the three following cases:

  • if the key is inferior to the key to be deleted, copy that element as is,
  • if the key is equal to the key to be deleted, skip that element,
  • if the key is superior to the key to be deleted, copy that element shifted by one to the left

Then you can assign that new dictionary to the old one.

HTH

Upvotes: 2

Use list instead for a mutable sequence of 0-base-indexed elements:

trans_list = [ "Charlie", "Alan", "Jake", "Rose" ]
del_key = raw_input('What key to delete')
del trans_list[int(del_key)]

Upvotes: 0

d6bels
d6bels

Reputation: 1482

You cannot do that because of the definition of a dictionary :

It is best to think of a dictionary as an unordered set of key: value pairs

You might want to use a list to have something ordered.

However, you could get a list from you dictionary and sort it, then you will be able to re-order how you like. See How can I convert a Python dictionary to a list of tuples?.

Upvotes: 1

David Z
David Z

Reputation: 131560

For this you should be using a list, not a dictionary, because a list is a structure which natively maps numerical indices to elements. When you remove an element from a list using del transList[delkey], it automatically shifts remaining elements in the list down to maintain consecutive indices.

Upvotes: 8

Related Questions