Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Shifting dictionary elements

Tags:

python

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

like image 642
Jim Avatar asked Dec 20 '22 06:12

Jim


2 Answers

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.

like image 159
David Z Avatar answered Dec 22 '22 01:12

David Z


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

like image 45
zmo Avatar answered Dec 22 '22 01:12

zmo