简体   繁体   中英

Is there a function in Python that shuffle data by data blocks?

For example, as to

[1 2 3 4 5 6]

Shuffle the data while keeping data blocks(including 2 data) as before. And we'll acquire:

[3 4 1 2 5 6]

Any way in Python to do this?

A straightforward way to do this is using the following three steps:

  1. create blocks (a 2d-list);
  2. shuffle that list; and
  3. merge these lists again.

So:

import random

# Import data
data = [1,2,3,4,5,6]
blocksize = 2

# Create blocks
blocks = [data[i:i+blocksize] for i in range(0,len(data),blocksize)]
# shuffle the blocks
random.shuffle(blocks)
# concatenate the shuffled blocks
data[:] = [b for bs in blocks for b in bs]

If you do not want to store the data back in data , you can simply use:

data = [b for bs in blocks for b in bs]

For this data I obtained:

>>> data
[3, 4, 1, 2, 5, 6]

a second time:

>>> data
[5, 6, 1, 2, 3, 4]

You can use the random module and call the function random.shuffle() - this will shuffle every element in your list, so break your list into sublists before shuffling

import random, itertools

mylist = [1, 2, 3, 4, 5, 6]
blocks = [mylist[x:x+2] for x in range(0, len(mylist), 2)]
random.shuffle(blocks)
list(itertools.chain.from_iterable(blocks))
>> [3, 4, 1, 2, 5, 6]

With maximal usage of standard methods:

>>> import random, itertools
>>> a
[1, 2, 3, 4, 5, 6]

# group elements by 2
>>> grouped = list(zip(*[iter(a)]*2))
>>> grouped
[(1, 2), (3, 4), (5, 6)]

# shuffle groups
>>> random.shuffle(grouped)
>>> grouped
[(3, 4), (1, 2), (5, 6)]

# flatten groups to list
>>> list(itertools.chain.from_iterable(grouped))
[3, 4, 1, 2, 5, 6]

Simple way

import random
data = [1,2,3,4,5,6]
temp = range(len(data)/2)
random.shuffle(temp)
data_c = data[:]
for i, j in enumerate(temp):
    if not i == j:
        data_c[i*2],data_c[(i*2)+1] = data[j*2],data[(j*2)+1]
print(data_c)

Output

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

There are no builtins, but you can write a small helper to do that for you:

1- create the blocks
2- Shuffle them
3- flatten the blocks and return the resulting shuffled sequence.

    import random

    def shuffle_by_blocks(seq, blocksize):
        blocks = [seq[idx*blocksize: (idx+1)*blocksize] for idx in range(len(seq)//blocksize)]
        random.shuffle(blocks)
        return [elt for block in blocks for elt in block ]

    shuffle_by_blocks([1,2,3,4,5,6], 2)

output sample:

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

Somebody asked for a solution using numpy:

>>> import numpy as np
>>> a = np.array([1, 2, 3, 4, 5, 6])
>>> np.random.shuffle(a.reshape((-1, 2)))
>>> a
array([5, 6, 3, 4, 1, 2])

This shuffles the reshaped view in place, but a keeps its original dimensions, so there's no need to reshape back.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM