Search code examples
pythondictionarydefaultdict

Shuffle a dictionary of lists aggregating by rows


I have a defaultfict(list) that might look like this

d = {0: [2, 4, 5], 1: [5, 6, 1]}

that I need to shuffle all the first elements from all of the lists together, and move one to the second and third rows. So in this example I need to take [2, 5], [4, 6], [5, 1] shuffle them and then put them back. At the end my dictionary might look like this

d = {0: [5, 4, 1], 1: [2, 6, 5]}

is there a pythonic way of doing this avoiding loops?

What I have until now is a way to extract and aggregate all the first, second, etc., elements of the lists and shuffle them using this

[random.sample([tmp_list[tmp_index] for tmp_list in d.values()], 2) for tmp_index in range(3)]

that will create the following

[[2, 5], [4, 6], [5, 1]]

and then in order to create my final shuffled-by-rows dictionary I use simple for loops.


Solution

    1. Get a transposed version of the dict values:

    >>> data = [list(v) for v in zip(*d.values())]    
    >>> data
    [[2, 5], [4, 6], [5, 1]]
    
    1. Shuffle them in-place

    >>> for x in data:
    ...     random.shuffle(x)
    ...
    
    >>> data
    [[5, 2], [4, 6], [5, 1]]
    
    1. Transpose the data again

    >>> data = zip(*data)
    
    1. Assign the new values to the dict

    >>> for x, k in zip(data, d):
    ...     d[k][:] = x  # Could also be written as d[k] = list(x)
    ...
    
    >>> d
    {0: [5, 4, 5], 1: [2, 6, 1]}