0

python's random.shuffle shuffle all or random no of elements? In present scenario only want to shuffle fixed number of elements as shown below

inp_list = [1,2,3,4,5,6,7,8,9]

# shuffle any 2 elements
op_list_1 = [1,2,3,4,9,6,7,8,5]

# shuffle any 4 element
op_list_4 = [8,2,5,4,3,6,7,1,9]

3 Answers3

1

A suggestion. See comments in code for further explanation. (The test list here has larger numbers than the one in the question, to avoid any confusion between the indices and the values.)

import random

inp_list = [11,12,13,14,15,16,17,18,19]

num = 3  # how many elements to shuffle

# obtain list of indices that will be shuffled
indices = random.sample(range(len(inp_list)), num)

# keep trying to build up a dictionary of mappings
# between old and new position, until it is successful
#
# Define "succcess" as meaning that no item is back in 
# its original position
#
shuffled_indices = indices.copy()
success = False
while not success:
    random.shuffle(shuffled_indices)
    mapping = { a:b for a, b in zip(indices, shuffled_indices) }
    for a, b in mapping.items():
        if a == b:
            success = False
            break
    else:
        success = True

# Now apply the mappings

out_list = inp_list.copy()
for a, b in mapping.items():
    out_list[a] = inp_list[b]

print(out_list)
alani
  • 12,573
  • 2
  • 13
  • 23
1

Here's what I came up with. Sample indices to be shuffled, shuffle them and replace the old list with the new values.

def shuffle(input_list, count=2):
    '''Shuffles any n number of values in a list'''
    indices_to_shuffle = random.sample(range(len(input_list)), k=count)
    to_shuffle = [input_list[i] for i in indices_to_shuffle]
    random.shuffle(to_shuffle)
    for index, value in enumerate(to_shuffle):
        old_index = indices_to_shuffle[index]
        input_list[old_index] = value
    return input_list
>>> shuffle([11, 22, 33, 44, 55, 66, 77, 88, 99])
[11, 88, 33, 44, 55, 66, 77, 22, 99]
  • It seems that we have broadly similar approaches for getting the initial list of indices, but then we diverge because I assumed that an attempted shuffle in which some elements randomly happen to end up in their original positions would not count -- i.e. we want "count" elements to definitely change position. The only way I could think of avoiding this was just trying repeatedly until it is successful -- which could be quite slow if it is shuffling a large number of elements (likely to fail so many retries needed). I would be interested if you can think of a more efficient way to do that. – alani Aug 16 '20 at 09:11
-1

shuffle all, then merge partially the original one with a shuffled (perhaps using a bitmap with n 1s and rest 0s)

ivan866
  • 554
  • 4
  • 10
  • Why don't you show usage with some code.. – sushanth Aug 16 '20 at 08:54
  • 1
    @sushanth It wouldn't work anyway. Simple example: suppose list has 3 elements and we want to shuffle 2 of them. Shuffle all: `a,b,c -> b,c,a`. Then applying bitmap `1,1,0` to do partial merge gives `b,c,c`, which is not a shuffled version of the initial list. – alani Aug 16 '20 at 09:20
  • @alaniwi, slice the original array with a bitmap, shuffle, insert back again on same indices – ivan866 Aug 16 '20 at 10:00