How to shuffle noncontiguous elements of a list?

Viewed 103

I have a list like the following in Python:

["Apple", "Banana", "Coconut", "Durian", "Elderberry", "Fig", "Guava"]

My goal is to shuffle the list so that certain elements are shuffled while others are left in their original place.

For instance, if the 0th, 1st, 2nd, 4th, and 6th elements are to be shuffled, a possible result of the shuffle would be:

["Elderberry", "Banana", "Apple", "Durian", "Guava", "Fig", "Coconut"]

How can I go about this? random.shuffle seems to only support a single object/slice. Shuffling each slice individually would only shuffle between each slice, rather than all the slices.

4 Answers

This does the trick -- it returns a new copy of the list unlike random.shuffle() though.

import random


def shuffle_some(source, shuffle_indices):
    # Get the things to shuffle by the given indices
    to_shuffle = [source[i] for i in shuffle_indices]
    # and shuffle them.
    random.shuffle(to_shuffle)

    # Take a shallow copy of the source list so we can
    # modify it...
    shuffled = source[:]
    # And iterate through pairs of indices in the `to_shuffle`
    # list and the target indices to place them...
    for i, source_index in enumerate(shuffle_indices):
        # ... and put the shuffled items into place.
        shuffled[source_index] = to_shuffle[i]
    return shuffled


s = ["Apple", "Banana", "Coconut", "Durian", "Elderberry", "Fig", "Guava"]

for x in range(5):
    print(shuffle_some(s, (0, 3, 4)))

The output is e.g.

['Elderberry', 'Banana', 'Coconut', 'Apple', 'Durian', 'Fig', 'Guava']
['Durian', 'Banana', 'Coconut', 'Apple', 'Elderberry', 'Fig', 'Guava']
['Apple', 'Banana', 'Coconut', 'Durian', 'Elderberry', 'Fig', 'Guava']
['Apple', 'Banana', 'Coconut', 'Durian', 'Elderberry', 'Fig', 'Guava']
['Apple', 'Banana', 'Coconut', 'Elderberry', 'Durian', 'Fig', 'Guava']

Think of it like splitting a stack of cards into two piles -- the pile you want to shuffle, and the pile whose order you want to preserve. Lay out the cards from the second pile in their original positions, shuffle the first pile, and then deal the shuffled pile into the remaining spaces.

>>> import random
>>> fruits = ["Apple", "Banana", "Coconut", "Durian", "Elderberry", "Fig", "Guava"]
>>> shuffle_indices = (0, 1, 2, 4, 6)
>>> shuffled_items = random.sample([f for i, f in enumerate(fruits) if i in shuffle_indices], len(shuffle_indices))
>>> shuffled_fruits = [shuffled_items.pop() if i in shuffle_indices else f for i, f in enumerate(fruits)]
>>> shuffled_fruits
['Banana', 'Guava', 'Coconut', 'Durian', 'Apple', 'Fig', 'Elderberry']

You can hard code this yourself.

You can extract which values you want to shuffle, and then shuffle those. Then, reenter them into the original.

def my_shuffle(list_, *args):
    shuffle_these = []
    for i in args:
        shuffle_these.append(list_[i])
    random.shuffle(shuffle_these)
    for integer, i in enumerate(list_):
        if integer in args:
            value = args.index(integer)
            list_[integer] = shuffle_these[value]
    return list_

print(my_shuffle([1, 2, 3, 4, 5, 6, 7], 1, 3, 6)) #this will shuffle the indices 1, 3, and 6

Result:

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

Something simpler as follows would do the trick:

from random import shuffle

def funct(all_elem, indices):
    to_shuffel = all_elem.copy()
    for index in sorted(indices, reverse=True):
        del to_shuffel[index]

    shuffle(to_shuffel)
    for index in indices:  # Add the static elements to the shuffled list, accordingly.
        to_shuffel.insert(index, all_elem[index])
    return to_shuffel
    

Create a function that receives the list to shuffle, and a group of indices, those indices will tell which part of the list should be kept unchanged. Create a list with the elements that can be shuffled, shuffle them, and at the end insert the fix elements to their correct index on the new shuffled list.

For :

list = ["Apple", "Banana", "Coconut", "Durian", "Elderberry", "Fig", "Guava"]
print(funct(list, (0, 1)))

Output:

['Apple', 'Banana', 'Fig', 'Elderberry', 'Durian', 'Coconut', 'Guava']
Related