Rotate values of a dictionary

Viewed 1517

Input :- {34: 'apple', 65: 'ball', 32: 'cat', 78: 'dog'}

Output :- {34: 'dog', 65: 'apple', 32: 'ball', 78: 'cat'}

I have come up with the following approach but is there any faster way to perform this task?

def rotate_values(my_dict):
    keys_list = list(my_dict.keys())
    values_list = list(my_dict.values())
    values_list.insert(0, values_list.pop())
    my_dict = dict(zip(keys_list, values_list))
    return my_dict
6 Answers

Your approach is linear, which you cannot improve as you have to rebind each key. You do not, however, have to transform the keys to a list (zip will work with any iterable), and you should use a deque for the rotation as it supports O(1) operations on both ends and thus constant time rotation:

from collections import deque

def rotate_values(my_dict):
    # no need to cast the keys to list
    values_deque = deque(my_dict.values())
    values_deque.rotate(1)
    return dict(zip(my_dict.keys(), values_deque))

Keep in mind that this process is not deterministic as dicts are unordered. Repeating it len(my_dict) times will not necessarily produce the original.

You can unpack the values into the last value and the rest, and then re-pack them as a sequence with last value in the front:

def rotate_values(my_dict):
    if not my_dict:
        return {}
    *rest, last = my_dict.values()
    return dict(zip(my_dict, (last, *rest)))

You can take values from my_dict and create a list. As you wander items of my_dict, you can assign values from values list to my_dict items's values.

my_dict = {34: 'apple', 65: 'ball', 32: 'cat', 78: 'dog'}

values = list(my_dict.values())
i = len(values)-1
for item in my_dict:
    my_dict[item] = values[i]
    i -= 1

print(my_dict)

this my version:

ks = list(d1.keys()) # [34, 65, 32, 78]

d2 = [d1[x] for x in d1.keys()][::-1] # ['dog', 'cat', 'ball', 'apple']

result = {x[0]:x[1] for x in list(zip(ks,d2))} #  {34: 'dog', 65: 'cat', 32: 'ball', 78: 'apple'}
from collections import deque


def rotate(d, n=1):
    """
    @param d: input python dictionary
    @param n: number of times to rotate it; default:1

    @return do: output dict rotated n times
    ex: d = {34: 'apple', 65: 'ball', 32: 'cat', 78: 'dog'}
        rotate(d, 1) -> {34: 'dog', 65: 'apple', 32: 'ball', 78: 'cat'}
    """

    # Get the values of the dict and put them into a deque collection that contains a rotate method
    do = deque(d.values())
    do.rotate(n)  # rotate the values by n
    do = dict(zip(d.keys(), do))  # recombine the keys and values

    return do

Demo:

In [1]: d = {34: 'apple', 65: 'ball', 32: 'cat', 78: 'dog'}

In [2]: rotate(d)
Out[2]: {34: 'dog', 65: 'apple', 32: 'ball', 78: 'cat'}

you could also use iterators to do the cycling:

from itertools import chain

def rotate_values(my_dict):
    keys = iter(my_dict.keys())
    keys = chain(keys, [next(keys)])
    return dict(zip(keys, my_dict.values()))

which does the right thing for me, giving:

{65: 'apple', 32: 'ball', 78: 'cat', 34: 'dog'}

as stated elsewhere dictionaries aren't ordered, so the utility of this code is debatable, but thought it would be interesting to show another way of solving this

Related